diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index f7ae5b88de..e7dbaa8a81 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -2188,6 +2188,29 @@ _nm_utils_strv_cleanup (char **strv, /*****************************************************************************/ +GPtrArray * +_nm_g_ptr_array_copy (GPtrArray *array, + GCopyFunc func, + gpointer user_data, + GDestroyNotify element_free_func) +{ + GPtrArray *new_array; + guint i; + + g_return_val_if_fail (array, NULL); + + new_array = g_ptr_array_new_full (array->len, element_free_func); + for (i = 0; i < array->len; i++) { + g_ptr_array_add (new_array, + func + ? func (array->pdata[i], user_data) + : array->pdata[i]); + } + return new_array; +} + +/*****************************************************************************/ + int _nm_utils_ascii_str_to_bool (const char *str, int default_value) diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 6aafd09e98..2f6681cb70 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -525,6 +525,14 @@ char **_nm_utils_strv_cleanup (char **strv, /*****************************************************************************/ +static inline gpointer +nm_copy_func_g_strdup (gconstpointer arg, gpointer user_data) +{ + return g_strdup (arg); +} + +/*****************************************************************************/ + static inline const char ** nm_utils_escaped_tokens_split (const char *str, const char *delimiters) @@ -1539,6 +1547,41 @@ nm_g_ptr_array_len (const GPtrArray *arr) return arr ? arr->len : 0u; } +GPtrArray *_nm_g_ptr_array_copy (GPtrArray *array, + GCopyFunc func, + gpointer user_data, + GDestroyNotify element_free_func); + +/** + * nm_g_ptr_array_copy: + * @array: the #GPtrArray to clone. + * @func: the copy function. + * @user_data: the user data for the copy function + * @element_free_func: the free function of the elements. @array MUST have + * the same element_free_func. This argument is only used on older + * glib, that doesn't support g_ptr_array_copy(). + * + * This is a replacement for g_ptr_array_copy(), which is not available + * before glib 2.62. Since GPtrArray does not allow to access the internal + * element_free_func, we cannot add a compatibility implementation of g_ptr_array_copy() + * and the user must provide a suitable destroy function. + * + * Note that the @element_free_func MUST correspond to free function set in @array. + */ +#if GLIB_CHECK_VERSION(2,62,0) +#define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \ + ({ \ + _nm_unused GDestroyNotify const _element_free_func = (element_free_func); \ + \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; \ + g_ptr_array_copy ((array), (func), (user_data)); \ + G_GNUC_END_IGNORE_DEPRECATIONS; \ + }) +#else +#define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \ + _nm_g_ptr_array_copy ((array), (func), (user_data), (element_free_func)) +#endif + /*****************************************************************************/ static inline guint @@ -1766,6 +1809,16 @@ nm_strv_ptrarray_ensure (GPtrArray **p_arr) return *p_arr; } +static inline GPtrArray * +nm_strv_ptrarray_clone (const GPtrArray *src, gboolean null_if_empty) +{ + if ( !src + || ( null_if_empty + && src->len == 0)) + return NULL; + return nm_g_ptr_array_copy ((GPtrArray *) src, nm_copy_func_g_strdup, NULL, g_free); +} + static inline void nm_strv_ptrarray_add_string_take (GPtrArray *cmd, char *str) diff --git a/shared/nm-std-aux/nm-std-aux.h b/shared/nm-std-aux/nm-std-aux.h index 91cd6c37fa..01409cefbb 100644 --- a/shared/nm-std-aux/nm-std-aux.h +++ b/shared/nm-std-aux/nm-std-aux.h @@ -125,6 +125,12 @@ #define nm_assert_not_reached() do { ; } while (0) #endif +#define nm_assert_unreachable_val(val) \ + ({ \ + nm_assert_not_reached (); \ + (val); \ + }) + #define NM_STATIC_ASSERT(cond) static_assert(cond, "") #define NM_STATIC_ASSERT_EXPR(cond) ({ NM_STATIC_ASSERT (cond); 1; }) diff --git a/shared/nm-utils/nm-test-utils.h b/shared/nm-utils/nm-test-utils.h index c270d2b941..b43e233007 100644 --- a/shared/nm-utils/nm-test-utils.h +++ b/shared/nm-utils/nm-test-utils.h @@ -984,6 +984,50 @@ nmtst_rand_perm_gslist (GRand *rand, GSList *list) return result; } +static inline void +nmtst_stable_rand (guint64 seed, + gpointer buf, + gsize len) +{ + const guint64 C = 1442695040888963407llu; + const guint64 A = 6364136223846793005llu; + guint8 *b; + union { + guint8 a[sizeof (guint64)]; + guint64 n; + } n; + + /* We want a stable random generator that is in our control and does not + * depend on glibc/glib versions. + * Use a linear congruential generator (x[n+1] = (A * x[n] + C) % M) + * https://en.wikipedia.org/wiki/Linear_congruential_generator + * + * We choose (Knuth’s LCG MMIX) + * A = 6364136223846793005llu + * C = 1442695040888963407llu + * M = 2^64 + */ + + g_assert (len == 0 || buf); + + n.n = seed; + b = buf; + for (; len > 0; len--, b++) { + n.n = (A * n.n + C); + + /* let's combine the 64 bits randomness in one byte. By xor-ing, it's + * also independent of endianness. */ + b[0] = n.a[0] + ^ n.a[1] + ^ n.a[2] + ^ n.a[3] + ^ n.a[4] + ^ n.a[5] + ^ n.a[6] + ^ n.a[7]; + } +} + /*****************************************************************************/ /** diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 91b0edfd50..8950f01bde 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -6169,6 +6169,26 @@ nm_device_master_update_slave_connection (NMDevice *self, return FALSE; } +static gboolean +_get_maybe_ipv6_disabled (NMDevice *self) +{ + NMPlatform *platform; + int ifindex; + const char *path; + char ifname[IFNAMSIZ]; + + ifindex = nm_device_get_ip_ifindex (self); + if (ifindex <= 0) + return FALSE; + + platform = nm_device_get_platform (self); + if (!nm_platform_if_indextoname (platform, ifindex, ifname)) + return FALSE; + + path = nm_sprintf_bufa (128, "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname); + return (nm_platform_sysctl_get_int32 (platform, NMP_SYSCTL_PATHID_ABSOLUTE (path), 0) == 0); +} + NMConnection * nm_device_generate_connection (NMDevice *self, NMDevice *master, @@ -6237,7 +6257,7 @@ nm_device_generate_connection (NMDevice *self, s_ip4 = nm_ip4_config_create_setting (priv->ip_config_4); nm_connection_add_setting (connection, s_ip4); - s_ip6 = nm_ip6_config_create_setting (priv->ip_config_6); + s_ip6 = nm_ip6_config_create_setting (priv->ip_config_6, _get_maybe_ipv6_disabled (self)); nm_connection_add_setting (connection, s_ip6); nm_connection_add_setting (connection, nm_setting_proxy_new ()); @@ -13415,9 +13435,10 @@ nm_device_set_ip_config (NMDevice *self, new_connection = nm_simple_connection_new_clone (nm_settings_connection_get_connection (settings_connection)); nm_connection_add_setting (new_connection, - IS_IPv4 - ? nm_ip4_config_create_setting (priv->ip_config_4) - : nm_ip6_config_create_setting (priv->ip_config_6)); + IS_IPv4 + ? nm_ip4_config_create_setting (priv->ip_config_4) + : nm_ip6_config_create_setting (priv->ip_config_6, + _get_maybe_ipv6_disabled (self))); nm_settings_connection_update (settings_connection, new_connection, diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index d186405672..75e0941aa9 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -3829,17 +3829,6 @@ nm_utils_ifname_cpy (char *dst, const char *name) /*****************************************************************************/ -#define IPV4LL_NETWORK (htonl (0xA9FE0000L)) -#define IPV4LL_NETMASK (htonl (0xFFFF0000L)) - -gboolean -nm_utils_ip4_address_is_link_local (in_addr_t addr) -{ - return (addr & IPV4LL_NETMASK) == IPV4LL_NETWORK; -} - -/*****************************************************************************/ - /** * Takes a pair @timestamp and @duration, and returns the remaining duration based * on the new timestamp @now. diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 190a81aa81..5d36bd593c 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -446,7 +446,18 @@ guint32 nm_utils_lifetime_get (guint32 timestamp, gint32 now, guint32 *out_preferred); -gboolean nm_utils_ip4_address_is_link_local (in_addr_t addr); +/*****************************************************************************/ + +#define NM_IPV4LL_NETWORK ((in_addr_t) (htonl (0xA9FE0000lu))) +#define NM_IPV4LL_NETMASK ((in_addr_t) (htonl (0xFFFF0000lu))) + +static inline gboolean +nm_utils_ip4_address_is_link_local (in_addr_t addr) +{ + return (addr & NM_IPV4LL_NETMASK) == NM_IPV4LL_NETWORK; +} + +/*****************************************************************************/ const char *nm_utils_dnsmasq_status_to_string (int status, char *dest, gsize size); diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index bd09ed511f..4a9026cdb3 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -505,48 +505,11 @@ _notify_routes (NMIP4Config *self) /*****************************************************************************/ -static int -_addresses_sort_cmp_get_prio (in_addr_t addr) -{ - if (nm_utils_ip4_address_is_link_local (addr)) - return 0; - return 1; -} - static int _addresses_sort_cmp (gconstpointer a, gconstpointer b, gpointer user_data) { - int p1, p2; - const NMPlatformIP4Address *a1 = NMP_OBJECT_CAST_IP4_ADDRESS (*((const NMPObject **) a)); - const NMPlatformIP4Address *a2 = NMP_OBJECT_CAST_IP4_ADDRESS (*((const NMPObject **) b)); - guint32 n1, n2; - - nm_assert (a1); - nm_assert (a2); - - /* Sort by address type. For example link local will - * be sorted *after* a global address. */ - p1 = _addresses_sort_cmp_get_prio (a1->address); - p2 = _addresses_sort_cmp_get_prio (a2->address); - if (p1 != p2) - return p1 > p2 ? -1 : 1; - - /* Sort the addresses based on their source. */ - if (a1->addr_source != a2->addr_source) - return a1->addr_source > a2->addr_source ? -1 : 1; - - if ((a1->label[0] == '\0') != (a2->label[0] == '\0')) - return (a1->label[0] == '\0') ? -1 : 1; - - /* Finally, sort addresses lexically. We compare only the - * network part so that the order of addresses in the same - * subnet (and thus also the primary/secondary role) is - * preserved. - */ - n1 = a1->address & _nm_utils_ip4_prefix_to_netmask (a1->plen); - n2 = a2->address & _nm_utils_ip4_prefix_to_netmask (a2->plen); - - return memcmp (&n1, &n2, sizeof (guint32)); + return nm_platform_ip4_address_pretty_sort_cmp (NMP_OBJECT_CAST_IP4_ADDRESS (*((const NMPObject **) a)), + NMP_OBJECT_CAST_IP4_ADDRESS (*((const NMPObject **) b))); } /*****************************************************************************/ @@ -1694,8 +1657,8 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev const NMPlatformIP4Address *r_src = NULL; const NMPlatformIP4Address *r_dst = NULL; - has = nm_ip_config_iter_ip4_address_next (&ipconf_iter_src, &r_src); - if (has != nm_ip_config_iter_ip4_address_next (&ipconf_iter_dst, &r_dst)) { + has = nm_platform_dedup_multi_iter_next_ip4_address (&ipconf_iter_src, &r_src); + if (has != nm_platform_dedup_multi_iter_next_ip4_address (&ipconf_iter_dst, &r_dst)) { are_equal = FALSE; has_relevant_changes = TRUE; break; @@ -1741,8 +1704,8 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev const NMPlatformIP4Route *r_src = NULL; const NMPlatformIP4Route *r_dst = NULL; - has = nm_ip_config_iter_ip4_route_next (&ipconf_iter_src, &r_src); - if (has != nm_ip_config_iter_ip4_route_next (&ipconf_iter_dst, &r_dst)) { + has = nm_platform_dedup_multi_iter_next_ip4_route (&ipconf_iter_src, &r_src); + if (has != nm_platform_dedup_multi_iter_next_ip4_route (&ipconf_iter_dst, &r_dst)) { are_equal = FALSE; has_relevant_changes = TRUE; break; diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index f1c4a57e85..04a0cfa5fe 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -35,36 +35,14 @@ void nm_ip_config_dedup_multi_idx_type_init (NMIPConfigDedupMultiIdxType *idx_ty void nm_ip_config_iter_ip4_address_init (NMDedupMultiIter *iter, const NMIP4Config *self); void nm_ip_config_iter_ip4_route_init (NMDedupMultiIter *iter, const NMIP4Config *self); -static inline gboolean -nm_ip_config_iter_ip4_address_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP4Address **out_address) -{ - gboolean has_next; - - has_next = nm_dedup_multi_iter_next (ipconf_iter); - if (out_address) - *out_address = has_next ? NMP_OBJECT_CAST_IP4_ADDRESS (ipconf_iter->current->obj) : NULL; - return has_next; -} - -static inline gboolean -nm_ip_config_iter_ip4_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP4Route **out_route) -{ - gboolean has_next; - - has_next = nm_dedup_multi_iter_next (ipconf_iter); - if (out_route) - *out_route = has_next ? NMP_OBJECT_CAST_IP4_ROUTE (ipconf_iter->current->obj) : NULL; - return has_next; -} - #define nm_ip_config_iter_ip4_address_for_each(iter, self, address) \ for (nm_ip_config_iter_ip4_address_init ((iter), (self)); \ - nm_ip_config_iter_ip4_address_next ((iter), (address)); \ + nm_platform_dedup_multi_iter_next_ip4_address ((iter), (address)); \ ) #define nm_ip_config_iter_ip4_route_for_each(iter, self, route) \ for (nm_ip_config_iter_ip4_route_init ((iter), (self)); \ - nm_ip_config_iter_ip4_route_next ((iter), (route)); \ + nm_platform_dedup_multi_iter_next_ip4_route ((iter), (route)); \ ) /*****************************************************************************/ diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 6c15e99765..00865734c5 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -64,7 +64,6 @@ typedef struct { NMDedupMultiIdxType idx_ip6_routes; }; NMIPConfigFlags config_flags; - bool ipv6_disabled; } NMIP6ConfigPrivate; struct _NMIP6Config { @@ -213,103 +212,20 @@ _notify_routes (NMIP6Config *self) /*****************************************************************************/ -static int -_addresses_sort_cmp_get_prio (const struct in6_addr *addr) -{ - if (IN6_IS_ADDR_V4MAPPED (addr)) - return 0; - if (IN6_IS_ADDR_V4COMPAT (addr)) - return 1; - if (IN6_IS_ADDR_UNSPECIFIED (addr)) - return 2; - if (IN6_IS_ADDR_LOOPBACK (addr)) - return 3; - if (IN6_IS_ADDR_LINKLOCAL (addr)) - return 4; - if (IN6_IS_ADDR_SITELOCAL (addr)) - return 5; - return 6; -} - -static int -_addresses_sort_cmp (const NMPlatformIP6Address *a1, - const NMPlatformIP6Address *a2, - gboolean prefer_temp) -{ - int p1, p2, c; - gboolean perm1, perm2, tent1, tent2; - gboolean ipv6_privacy1, ipv6_privacy2; - - /* tentative addresses are always sorted back... */ - /* sort tentative addresses after non-tentative. */ - tent1 = (a1->n_ifa_flags & IFA_F_TENTATIVE); - tent2 = (a2->n_ifa_flags & IFA_F_TENTATIVE); - if (tent1 != tent2) - return tent1 ? 1 : -1; - - /* Sort by address type. For example link local will - * be sorted *after* site local or global. */ - p1 = _addresses_sort_cmp_get_prio (&a1->address); - p2 = _addresses_sort_cmp_get_prio (&a2->address); - if (p1 != p2) - return p1 > p2 ? -1 : 1; - - ipv6_privacy1 = !!(a1->n_ifa_flags & (IFA_F_MANAGETEMPADDR | IFA_F_TEMPORARY)); - ipv6_privacy2 = !!(a2->n_ifa_flags & (IFA_F_MANAGETEMPADDR | IFA_F_TEMPORARY)); - if (ipv6_privacy1 || ipv6_privacy2) { - gboolean public1 = TRUE, public2 = TRUE; - - if (ipv6_privacy1) { - if (a1->n_ifa_flags & IFA_F_TEMPORARY) - public1 = prefer_temp; - else - public1 = !prefer_temp; - } - if (ipv6_privacy2) { - if (a2->n_ifa_flags & IFA_F_TEMPORARY) - public2 = prefer_temp; - else - public2 = !prefer_temp; - } - - if (public1 != public2) - return public1 ? -1 : 1; - } - - /* Sort the addresses based on their source. */ - if (a1->addr_source != a2->addr_source) - return a1->addr_source > a2->addr_source ? -1 : 1; - - /* sort permanent addresses before non-permanent. */ - perm1 = (a1->n_ifa_flags & IFA_F_PERMANENT); - perm2 = (a2->n_ifa_flags & IFA_F_PERMANENT); - if (perm1 != perm2) - return perm1 ? -1 : 1; - - /* finally sort addresses lexically */ - c = memcmp (&a1->address, &a2->address, sizeof (a2->address)); - return c != 0 ? c : memcmp (a1, a2, sizeof (*a1)); -} - static int _addresses_sort_cmp_prop (gconstpointer a, gconstpointer b, gpointer user_data) { - return _addresses_sort_cmp (NMP_OBJECT_CAST_IP6_ADDRESS (*((const NMPObject **) a)), - NMP_OBJECT_CAST_IP6_ADDRESS (*((const NMPObject **) b)), - ((NMSettingIP6ConfigPrivacy) GPOINTER_TO_INT (user_data)) == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR); + return nm_platform_ip6_address_pretty_sort_cmp (NMP_OBJECT_CAST_IP6_ADDRESS (*((const NMPObject **) a)), + NMP_OBJECT_CAST_IP6_ADDRESS (*((const NMPObject **) b)), + (((NMSettingIP6ConfigPrivacy) GPOINTER_TO_INT (user_data)) == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR)); } static int sort_captured_addresses (const CList *lst_a, const CList *lst_b, gconstpointer user_data) { - const NMPlatformIP6Address *addr_a = NMP_OBJECT_CAST_IP6_ADDRESS (c_list_entry (lst_a, NMDedupMultiEntry, lst_entries)->obj); - const NMPlatformIP6Address *addr_b = NMP_OBJECT_CAST_IP6_ADDRESS (c_list_entry (lst_b, NMDedupMultiEntry, lst_entries)->obj); - - nm_assert (addr_a); - nm_assert (addr_b); - - return _addresses_sort_cmp (addr_a, addr_b, - ((NMSettingIP6ConfigPrivacy) GPOINTER_TO_INT (user_data)) == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR); + return nm_platform_ip6_address_pretty_sort_cmp (NMP_OBJECT_CAST_IP6_ADDRESS (c_list_entry (lst_a, NMDedupMultiEntry, lst_entries)->obj), + NMP_OBJECT_CAST_IP6_ADDRESS (c_list_entry (lst_b, NMDedupMultiEntry, lst_entries)->obj), + (((NMSettingIP6ConfigPrivacy) GPOINTER_TO_INT (user_data)) == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR)); } gboolean @@ -373,8 +289,6 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i const NMDedupMultiHeadEntry *head_entry; NMDedupMultiIter iter; const NMPObject *plobj = NULL; - char ifname[IFNAMSIZ]; - char *path; nm_assert (ifindex > 0); @@ -416,12 +330,6 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i nmp_cache_iter_for_each (&iter, head_entry, &plobj) _add_route (self, plobj, NULL, NULL); - if (nm_platform_if_indextoname (platform, ifindex, ifname)) { - path = nm_sprintf_bufa (128, "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname); - if (nm_platform_sysctl_get_int32 (platform, NMP_SYSCTL_PATHID_ABSOLUTE (path), 0) != 0) - priv->ipv6_disabled = TRUE; - } - return self; } @@ -757,7 +665,7 @@ nm_ip6_config_merge_setting (NMIP6Config *self, } NMSetting * -nm_ip6_config_create_setting (const NMIP6Config *self) +nm_ip6_config_create_setting (const NMIP6Config *self, gboolean maybe_ipv6_disabled) { const NMIP6ConfigPrivate *priv; NMSettingIPConfig *s_ip6; @@ -822,7 +730,7 @@ nm_ip6_config_create_setting (const NMIP6Config *self) /* Use 'ignore' if the method wasn't previously set */ if (!method) { - method = priv->ipv6_disabled + method = maybe_ipv6_disabled ? NM_SETTING_IP6_CONFIG_METHOD_DISABLED : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; } @@ -893,13 +801,11 @@ nm_ip6_config_merge (NMIP6Config *dst, NMDedupMultiIter ipconf_iter; const NMPlatformIP6Address *address = NULL; const NMIP6ConfigPrivate *src_priv; - NMIP6ConfigPrivate *dst_priv; g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); src_priv = NM_IP6_CONFIG_GET_PRIVATE (src); - dst_priv = NM_IP6_CONFIG_GET_PRIVATE (dst); g_object_freeze_notify (G_OBJECT (dst)); @@ -965,9 +871,6 @@ nm_ip6_config_merge (NMIP6Config *dst, if (nm_ip6_config_get_dns_priority (src)) nm_ip6_config_set_dns_priority (dst, nm_ip6_config_get_dns_priority (src)); - if (src_priv->ipv6_disabled) - dst_priv->ipv6_disabled = src_priv->ipv6_disabled; - g_object_thaw_notify (G_OBJECT (dst)); } @@ -1393,8 +1296,8 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev const NMPlatformIP6Address *r_src = NULL; const NMPlatformIP6Address *r_dst = NULL; - has = nm_ip_config_iter_ip6_address_next (&ipconf_iter_src, &r_src); - if (has != nm_ip_config_iter_ip6_address_next (&ipconf_iter_dst, &r_dst)) { + has = nm_platform_dedup_multi_iter_next_ip6_address (&ipconf_iter_src, &r_src); + if (has != nm_platform_dedup_multi_iter_next_ip6_address (&ipconf_iter_dst, &r_dst)) { are_equal = FALSE; has_relevant_changes = TRUE; break; @@ -1441,8 +1344,8 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev const NMPlatformIP6Route *r_src = NULL; const NMPlatformIP6Route *r_dst = NULL; - has = nm_ip_config_iter_ip6_route_next (&ipconf_iter_src, &r_src); - if (has != nm_ip_config_iter_ip6_route_next (&ipconf_iter_dst, &r_dst)) { + has = nm_platform_dedup_multi_iter_next_ip6_route (&ipconf_iter_src, &r_src); + if (has != nm_platform_dedup_multi_iter_next_ip6_route (&ipconf_iter_dst, &r_dst)) { are_equal = FALSE; has_relevant_changes = TRUE; break; @@ -1573,11 +1476,6 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev has_minor_changes = TRUE; } - if (src_priv->ipv6_disabled != dst_priv->ipv6_disabled) { - dst_priv->ipv6_disabled = src_priv->ipv6_disabled; - has_minor_changes = TRUE; - } - #if NM_MORE_ASSERTS /* config_equal does not compare *all* the fields, therefore, we might have has_minor_changes * regardless of config_equal. But config_equal must correspond to has_relevant_changes. */ diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index b6f461b29f..079005e477 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -18,36 +18,14 @@ void nm_ip_config_iter_ip6_address_init (NMDedupMultiIter *iter, const NMIP6Config *self); void nm_ip_config_iter_ip6_route_init (NMDedupMultiIter *iter, const NMIP6Config *self); -static inline gboolean -nm_ip_config_iter_ip6_address_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP6Address **out_address) -{ - gboolean has_next; - - has_next = nm_dedup_multi_iter_next (ipconf_iter); - if (out_address) - *out_address = has_next ? NMP_OBJECT_CAST_IP6_ADDRESS (ipconf_iter->current->obj) : NULL; - return has_next; -} - -static inline gboolean -nm_ip_config_iter_ip6_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP6Route **out_route) -{ - gboolean has_next; - - has_next = nm_dedup_multi_iter_next (ipconf_iter); - if (out_route) - *out_route = has_next ? NMP_OBJECT_CAST_IP6_ROUTE (ipconf_iter->current->obj) : NULL; - return has_next; -} - #define nm_ip_config_iter_ip6_address_for_each(iter, self, address) \ for (nm_ip_config_iter_ip6_address_init ((iter), (self)); \ - nm_ip_config_iter_ip6_address_next ((iter), (address)); \ + nm_platform_dedup_multi_iter_next_ip6_address ((iter), (address)); \ ) #define nm_ip_config_iter_ip6_route_for_each(iter, self, route) \ for (nm_ip_config_iter_ip6_route_init ((iter), (self)); \ - nm_ip_config_iter_ip6_route_next ((iter), (route)); \ + nm_platform_dedup_multi_iter_next_ip6_route ((iter), (route)); \ ) /*****************************************************************************/ @@ -105,7 +83,7 @@ void nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guint32 route_table, guint32 route_metric); -NMSetting *nm_ip6_config_create_setting (const NMIP6Config *self); +NMSetting *nm_ip6_config_create_setting (const NMIP6Config *self, gboolean maybe_ipv6_disabled); void nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, diff --git a/src/nm-l3-config-data.c b/src/nm-l3-config-data.c index d20df9dc36..23d2dd0fae 100644 --- a/src/nm-l3-config-data.c +++ b/src/nm-l3-config-data.c @@ -4,6 +4,9 @@ #include "nm-l3-config-data.h" +#include +#include + #include "nm-core-internal.h" #include "platform/nm-platform.h" #include "platform/nmp-object.h" @@ -43,6 +46,8 @@ struct _NML3ConfigData { const NMPObject *best_default_route_x[2]; }; + GArray *wins_4; + union { struct { GArray *nameservers_6; @@ -86,13 +91,100 @@ struct _NML3ConfigData { NMSettingConnectionMdns mdns; NMSettingConnectionLlmnr llmnr; + int ifindex; + int ref_count; + NML3ConfigDatFlags flags; + bool is_sealed:1; }; /*****************************************************************************/ +static GArray * +_garray_inaddr_ensure (GArray **p_arr, + int addr_family) +{ + nm_assert (p_arr); + nm_assert_addr_family (addr_family); + + if (G_UNLIKELY (!*p_arr)) { + *p_arr = g_array_new (FALSE, + FALSE, + nm_utils_addr_family_to_size (addr_family)); + } + return *p_arr; +} + +static GArray * +_garray_inaddr_clone (GArray *src, + int addr_family) +{ + const gsize elt_size = nm_utils_addr_family_to_size (addr_family); + GArray *dst; + + nm_assert_addr_family (addr_family); + + if ( !src + || src->len == 0) + return NULL; + + dst = g_array_sized_new (FALSE, FALSE, elt_size, src->len); + g_array_set_size (dst, src->len); + memcpy (dst->data, src->data, src->len * elt_size); + return dst; +} + +static gssize +_garray_inaddr_find (GArray *arr, + int addr_family, + gconstpointer needle, + /* (const NMIPAddr **) */ gpointer out_addr) +{ + guint i; + + nm_assert_addr_family (addr_family); + nm_assert (needle); + + if (arr) { + const gsize elt_size = nm_utils_addr_family_to_size (addr_family); + const char *p; + + p = arr->data; + for (i = 0; i < arr->len; i++, p += elt_size) { + if (memcmp (p, needle, elt_size) == 0) { + NM_SET_OUT ((gconstpointer *) out_addr, p); + return i; + } + } + } + NM_SET_OUT ((gconstpointer *) out_addr, NULL); + return -1; +} + +static gboolean +_garray_inaddr_add (GArray **p_arr, + int addr_family, + gconstpointer addr) +{ + nm_assert (p_arr); + nm_assert_addr_family (addr_family); + nm_assert (addr); + + if (!*p_arr) + _garray_inaddr_ensure (p_arr, addr_family); + else { + if (_garray_inaddr_find (*p_arr, addr_family, addr, NULL) >= 0) + return FALSE; + } + + g_array_append_vals (*p_arr, addr, 1); + return TRUE; +} + +/*****************************************************************************/ + static gboolean _route_valid_4 (const NMPlatformIP4Route *r) { @@ -126,27 +218,16 @@ _route_valid (int addr_family, gconstpointer r) static gboolean NM_IS_L3_CONFIG_DATA (const NML3ConfigData *self, gboolean allow_sealed) { + nm_assert ( !self + || ( self->ifindex > 0 + && self->multi_idx + && self->ref_count > 0)); return self && self->ref_count > 0 && ( allow_sealed || !self->is_sealed); } -static GArray * -_garray_ensure_for_addrbin (GArray **p_arr, - int addr_family) -{ - nm_assert (p_arr); - nm_assert_addr_family (addr_family); - - if (G_UNLIKELY (!*p_arr)) { - *p_arr = g_array_new (FALSE, - FALSE, - nm_utils_addr_family_to_size (addr_family)); - } - return *p_arr; -} - static void _idx_obj_id_hash_update (const NMDedupMultiIdxType *idx_type, const NMDedupMultiObj *obj, @@ -178,18 +259,22 @@ _idx_type_init (DedupMultiIdxType *idx_type, } NML3ConfigData * -nm_l3_config_data_new (NMDedupMultiIndex *multi_idx) +nm_l3_config_data_new (NMDedupMultiIndex *multi_idx, + int ifindex) { NML3ConfigData *self; nm_assert (multi_idx); + nm_assert (ifindex > 0); self = g_slice_new (NML3ConfigData); *self = (NML3ConfigData) { .ref_count = 1, + .ifindex = ifindex, .multi_idx = nm_dedup_multi_index_ref (multi_idx), .mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT, .llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT, + .flags = NM_L3_CONFIG_DAT_FLAGS_NONE, }; _idx_type_init (&self->idx_addresses_4, NMP_OBJECT_TYPE_IP4_ADDRESS); @@ -200,97 +285,146 @@ nm_l3_config_data_new (NMDedupMultiIndex *multi_idx) return self; } -NML3ConfigData * -nm_l3_config_data_ref (NML3ConfigData *self) +const NML3ConfigData * +nm_l3_config_data_ref (const NML3ConfigData *self) { nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); - self->ref_count++; + ((NML3ConfigData *) self)->ref_count++; return self; } -NML3ConfigData * -nm_l3_config_data_ref_and_seal (NML3ConfigData *self) +const NML3ConfigData * +nm_l3_config_data_ref_and_seal (const NML3ConfigData *self) { nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); - self->is_sealed = TRUE; - self->ref_count++; + ((NML3ConfigData *) self)->is_sealed = TRUE; + ((NML3ConfigData *) self)->ref_count++; return self; } -NML3ConfigData * -nm_l3_config_data_seal (NML3ConfigData *self) +const NML3ConfigData * +nm_l3_config_data_seal (const NML3ConfigData *self) { nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); - self->is_sealed = TRUE; + ((NML3ConfigData *) self)->is_sealed = TRUE; return self; } gboolean -nm_l3_config_data_is_sealed (NML3ConfigData *self) +nm_l3_config_data_is_sealed (const NML3ConfigData *self) { nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); return self->is_sealed; } void -nm_l3_config_data_unref (NML3ConfigData *self) +nm_l3_config_data_unref (const NML3ConfigData *self) { + NML3ConfigData *mutable; + if (!self) return; nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); - if (--self->ref_count > 0) + + /* NML3ConfigData aims to be an immutable, ref-counted type. The mode of operation + * is to create/initialize the instance once, then seal it and pass around the reference. + * + * That means, also ref/unref operate on const pointers (otherwise, you'd have to cast all + * the time). Hence, we cast away the constness during ref/unref/seal operations. */ + + mutable = (NML3ConfigData *) self; + + if (--mutable->ref_count > 0) return; - nm_dedup_multi_index_remove_idx (self->multi_idx, &self->idx_addresses_4.parent); - nm_dedup_multi_index_remove_idx (self->multi_idx, &self->idx_addresses_6.parent); - nm_dedup_multi_index_remove_idx (self->multi_idx, &self->idx_routes_4.parent); - nm_dedup_multi_index_remove_idx (self->multi_idx, &self->idx_routes_6.parent); + nm_dedup_multi_index_remove_idx (mutable->multi_idx, &mutable->idx_addresses_4.parent); + nm_dedup_multi_index_remove_idx (mutable->multi_idx, &mutable->idx_addresses_6.parent); + nm_dedup_multi_index_remove_idx (mutable->multi_idx, &mutable->idx_routes_4.parent); + nm_dedup_multi_index_remove_idx (mutable->multi_idx, &mutable->idx_routes_6.parent); - nmp_object_unref (self->best_default_route_4); - nmp_object_unref (self->best_default_route_6); + nmp_object_unref (mutable->best_default_route_4); + nmp_object_unref (mutable->best_default_route_6); - nm_clear_pointer (&self->nameservers_4, g_array_unref); - nm_clear_pointer (&self->nameservers_6, g_array_unref); + nm_clear_pointer (&mutable->wins_4, g_array_unref); - nm_clear_pointer (&self->domains_4, g_ptr_array_unref); - nm_clear_pointer (&self->domains_6, g_ptr_array_unref); + nm_clear_pointer (&mutable->nameservers_4, g_array_unref); + nm_clear_pointer (&mutable->nameservers_6, g_array_unref); - nm_clear_pointer (&self->searches_4, g_ptr_array_unref); - nm_clear_pointer (&self->searches_6, g_ptr_array_unref); + nm_clear_pointer (&mutable->domains_4, g_ptr_array_unref); + nm_clear_pointer (&mutable->domains_6, g_ptr_array_unref); - nm_clear_pointer (&self->dns_options_4, g_ptr_array_unref); - nm_clear_pointer (&self->dns_options_6, g_ptr_array_unref); + nm_clear_pointer (&mutable->searches_4, g_ptr_array_unref); + nm_clear_pointer (&mutable->searches_6, g_ptr_array_unref); - nm_dedup_multi_index_unref (self->multi_idx); + nm_clear_pointer (&mutable->dns_options_4, g_ptr_array_unref); + nm_clear_pointer (&mutable->dns_options_6, g_ptr_array_unref); - nm_g_slice_free (self); + nm_dedup_multi_index_unref (mutable->multi_idx); + + nm_g_slice_free (mutable); } /*****************************************************************************/ const NMDedupMultiHeadEntry * -nm_l3_config_data_lookup_addresses (const NML3ConfigData *self, - int addr_family) +nm_l3_config_data_lookup_objs (const NML3ConfigData *self, NMPObjectType obj_type) { - nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); - nm_assert_addr_family (addr_family); + const DedupMultiIdxType *idx; - return nm_dedup_multi_index_lookup_head (self->multi_idx, - &self->idx_addresses_x[NM_IS_IPv4 (addr_family)].parent, - NULL); + nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); + + switch (obj_type) { + case NMP_OBJECT_TYPE_IP4_ADDRESS: + idx = &self->idx_addresses_4; + break; + case NMP_OBJECT_TYPE_IP6_ADDRESS: + idx = &self->idx_addresses_6; + break; + case NMP_OBJECT_TYPE_IP4_ROUTE: + idx = &self->idx_routes_4; + break; + case NMP_OBJECT_TYPE_IP6_ROUTE: + idx = &self->idx_routes_6; + break; + default: + nm_assert_not_reached (); + return NULL; + } + + return nm_dedup_multi_index_lookup_head (self->multi_idx, &idx->parent, NULL); } -const NMDedupMultiHeadEntry * -nm_l3_config_data_lookup_routes (const NML3ConfigData *self, - int addr_family) +/*****************************************************************************/ + +int +nm_l3_config_data_get_ifindex (const NML3ConfigData *self) { nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); - nm_assert_addr_family (addr_family); - return nm_dedup_multi_index_lookup_head (self->multi_idx, - &self->idx_routes_x[NM_IS_IPv4 (addr_family)].parent, - NULL); + return self->ifindex; +} + +/*****************************************************************************/ + +NML3ConfigDatFlags +nm_l3_config_data_get_flags (const NML3ConfigData *self) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, TRUE)); + + return self->flags; +} + +void +nm_l3_config_data_set_flags_full (NML3ConfigData *self, + NML3ConfigDatFlags flags, + NML3ConfigDatFlags mask) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert (!NM_FLAGS_ANY (flags, ~mask)); + + self->flags = (self->flags & ~mask) + | (flags & mask); } /*****************************************************************************/ @@ -312,12 +446,11 @@ _l3_config_data_add_obj (NMDedupMultiIndex *multi_idx, nm_assert (multi_idx); nm_assert (idx_type); + nm_assert (ifindex > 0); nm_assert (NM_IN_SET (idx_type->obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ADDRESS, NMP_OBJECT_TYPE_IP6_ROUTE)); - nm_assert (ifindex > 0); - /* we go through extra lengths to accept a full obj_new object. That one, * can be reused by increasing the ref-count. */ if (!obj_new) { @@ -474,6 +607,37 @@ _l3_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPOb return obj_cur; } +gboolean +nm_l3_config_data_add_address (NML3ConfigData *self, + int addr_family, + const NMPObject *obj_new, + const NMPlatformIPAddress *pl_new, + const NMPObject **out_obj_new) +{ + const NMPObject *new; + gboolean changed; + + nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert_addr_family (addr_family); + nm_assert ((!pl_new) != (!obj_new)); + nm_assert ( !obj_new + || NMP_OBJECT_GET_ADDR_FAMILY (obj_new) == addr_family); + + changed = _l3_config_data_add_obj (self->multi_idx, + addr_family == AF_INET + ? &self->idx_addresses_4 + : &self->idx_addresses_6, + self->ifindex, + obj_new, + (const NMPlatformObject *) pl_new, + TRUE, + FALSE, + NULL, + &new); + NM_SET_OUT (out_obj_new, nmp_object_ref (new)); + return changed; +} + static gboolean _l3_config_best_default_route_merge (const NMPObject **best_default_route, const NMPObject *new_candidate) { @@ -483,13 +647,12 @@ _l3_config_best_default_route_merge (const NMPObject **best_default_route, const } gboolean -_nm_l3_config_data_add_route (NML3ConfigData *self, - int addr_family, - int ifindex, - const NMPObject *obj_new, - const NMPlatformIPRoute *pl_new, - const NMPObject **out_obj_new, - gboolean *out_changed_best_default_route) +nm_l3_config_data_add_route (NML3ConfigData *self, + int addr_family, + const NMPObject *obj_new, + const NMPlatformIPRoute *pl_new, + const NMPObject **out_obj_new, + gboolean *out_changed_best_default_route) { const gboolean IS_IPv4 = NM_IS_IPv4 (addr_family); nm_auto_nmpobj const NMPObject *obj_old = NULL; @@ -497,8 +660,8 @@ _nm_l3_config_data_add_route (NML3ConfigData *self, gboolean changed = FALSE; gboolean changed_best_default_route = FALSE; + nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); nm_assert_addr_family (addr_family); - nm_assert (ifindex > 0); nm_assert ((!pl_new) != (!obj_new)); nm_assert ( !pl_new || _route_valid (addr_family, pl_new)); @@ -510,7 +673,7 @@ _nm_l3_config_data_add_route (NML3ConfigData *self, addr_family == AF_INET ? &self->idx_routes_4 : &self->idx_routes_6, - ifindex, + self->ifindex, obj_new, (const NMPlatformObject *) pl_new, TRUE, @@ -536,33 +699,6 @@ _nm_l3_config_data_add_route (NML3ConfigData *self, return changed; } -gboolean -_nm_l3_config_data_add_address (NML3ConfigData *self, - int addr_family, - int ifindex, - const NMPObject *obj_new, - const NMPlatformIPAddress *pl_new) -{ - nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); - nm_assert_addr_family (addr_family); - nm_assert (ifindex > 0); - nm_assert ((!pl_new) != (!obj_new)); - nm_assert ( !obj_new - || NMP_OBJECT_GET_ADDR_FAMILY (obj_new) == addr_family); - - return _l3_config_data_add_obj (self->multi_idx, - addr_family == AF_INET - ? &self->idx_addresses_4 - : &self->idx_addresses_6, - ifindex, - obj_new, - (const NMPlatformObject *) pl_new, - TRUE, - FALSE, - NULL, - NULL); -} - /*****************************************************************************/ static gboolean @@ -575,7 +711,7 @@ _check_and_add_domain (GPtrArray **p_arr, const char *domain) g_return_val_if_fail (domain, FALSE); if (domain[0] == '\0') - g_return_val_if_reached (FALSE); + return FALSE; if (domain[0] == '.' || strstr (domain, "..")) return FALSE; @@ -596,9 +732,34 @@ _check_and_add_domain (GPtrArray **p_arr, const char *domain) } gboolean -_nm_l3_config_data_add_domain (NML3ConfigData *self, - int addr_family, - const char *domain) +nm_l3_config_data_add_nameserver (NML3ConfigData *self, + int addr_family, + gconstpointer /* (const NMIPAddr *) */ nameserver) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert_addr_family (addr_family); + nm_assert (nameserver); + + return _garray_inaddr_add (&self->nameservers_x[NM_IS_IPv4 (addr_family)], + addr_family, + nameserver); +} + +gboolean +nm_l3_config_data_add_wins (NML3ConfigData *self, + in_addr_t wins) +{ + nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); + + return _garray_inaddr_add (&self->wins_4, + AF_INET, + &wins); +} + +gboolean +nm_l3_config_data_add_domain (NML3ConfigData *self, + int addr_family, + const char *domain) { nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); nm_assert_addr_family (addr_family); @@ -607,9 +768,9 @@ _nm_l3_config_data_add_domain (NML3ConfigData *self, } gboolean -_nm_l3_config_data_add_search (NML3ConfigData *self, - int addr_family, - const char *search) +nm_l3_config_data_add_search (NML3ConfigData *self, + int addr_family, + const char *search) { nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); nm_assert_addr_family (addr_family); @@ -618,9 +779,9 @@ _nm_l3_config_data_add_search (NML3ConfigData *self, } gboolean -_nm_l3_config_data_add_dns_option (NML3ConfigData *self, - int addr_family, - const char *dns_option) +nm_l3_config_data_add_dns_option (NML3ConfigData *self, + int addr_family, + const char *dns_option) { GPtrArray **p_arr; @@ -629,8 +790,8 @@ _nm_l3_config_data_add_dns_option (NML3ConfigData *self, g_return_val_if_fail (dns_option, FALSE); - if (!dns_option[0]) - g_return_val_if_reached (FALSE); + if (dns_option[0] == '\0') + return FALSE; p_arr = &self->dns_options_x[NM_IS_IPv4 (addr_family)]; @@ -643,9 +804,9 @@ _nm_l3_config_data_add_dns_option (NML3ConfigData *self, } gboolean -_nm_l3_config_data_set_dns_priority (NML3ConfigData *self, - int addr_family, - int dns_priority) +nm_l3_config_data_set_dns_priority (NML3ConfigData *self, + int addr_family, + int dns_priority) { int *p_val; @@ -665,7 +826,6 @@ _nm_l3_config_data_set_dns_priority (NML3ConfigData *self, static void _init_from_connection_ip (NML3ConfigData *self, int addr_family, - int ifindex, NMConnection *connection, guint32 route_table, guint32 route_metric) @@ -682,7 +842,6 @@ _init_from_connection_ip (NML3ConfigData *self, int idx; nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); - nm_assert (ifindex > 0); nm_assert_addr_family (addr_family); nm_assert (!connection || NM_IS_CONNECTION (connection)); @@ -715,7 +874,7 @@ _init_from_connection_ip (NML3ConfigData *self, }; } - _nm_l3_config_data_add_route (self, addr_family, ifindex, NULL, &r.rx, NULL, NULL); + nm_l3_config_data_add_route (self, addr_family, NULL, &r.rx, NULL, NULL); } naddresses = nm_setting_ip_config_get_num_addresses (s_ip); @@ -755,7 +914,7 @@ _init_from_connection_ip (NML3ConfigData *self, nm_assert (a.a6.plen <= 128); } - _nm_l3_config_data_add_address (self, addr_family, ifindex, NULL, &a.ax); + nm_l3_config_data_add_address (self, addr_family, NULL, &a.ax, NULL); } nroutes = nm_setting_ip_config_get_num_routes (s_ip); @@ -809,7 +968,7 @@ _init_from_connection_ip (NML3ConfigData *self, &r.rx, route_table); - _nm_l3_config_data_add_route (self, addr_family, ifindex, NULL, &r.rx, NULL, NULL); + nm_l3_config_data_add_route (self, addr_family, NULL, &r.rx, NULL, NULL); } nnameservers = nm_setting_ip_config_get_num_dns (s_ip); @@ -820,33 +979,31 @@ _init_from_connection_ip (NML3ConfigData *self, s = nm_setting_ip_config_get_dns (s_ip, i); if (!nm_utils_parse_inaddr_bin (addr_family, s, NULL, &ip)) continue; - g_array_append_vals (_garray_ensure_for_addrbin (&self->nameservers_x[IS_IPv4], addr_family), - &ip, - 1); + nm_l3_config_data_add_nameserver (self, addr_family, &ip); } nsearches = nm_setting_ip_config_get_num_dns_searches (s_ip); for (i = 0; i < nsearches; i++) { - _nm_l3_config_data_add_search (self, - addr_family, - nm_setting_ip_config_get_dns_search (s_ip, i)); + nm_l3_config_data_add_search (self, + addr_family, + nm_setting_ip_config_get_dns_search (s_ip, i)); } idx = 0; while ((idx = nm_setting_ip_config_next_valid_dns_option (s_ip, i)) >= 0) { - _nm_l3_config_data_add_dns_option (self, - addr_family, - nm_setting_ip_config_get_dns_option (s_ip, i)); + nm_l3_config_data_add_dns_option (self, + addr_family, + nm_setting_ip_config_get_dns_option (s_ip, i)); idx++; } - _nm_l3_config_data_set_dns_priority (self, - addr_family, - nm_setting_ip_config_get_dns_priority (s_ip)); + nm_l3_config_data_set_dns_priority (self, + addr_family, + nm_setting_ip_config_get_dns_priority (s_ip)); } NML3ConfigData * -nm_l3_config_data_new_from_connection (NMDedupMultiIndex *multi_index, +nm_l3_config_data_new_from_connection (NMDedupMultiIndex *multi_idx, int ifindex, NMConnection *connection, NMSettingConnectionMdns mdns, @@ -856,13 +1013,162 @@ nm_l3_config_data_new_from_connection (NMDedupMultiIndex *multi_index, { NML3ConfigData *self; - self = nm_l3_config_data_new (multi_index); + self = nm_l3_config_data_new (multi_idx, ifindex); - _init_from_connection_ip (self, AF_INET, ifindex, connection, route_table, route_metric); - _init_from_connection_ip (self, AF_INET6, ifindex, connection, route_table, route_metric); + _init_from_connection_ip (self, AF_INET, connection, route_table, route_metric); + _init_from_connection_ip (self, AF_INET6, connection, route_table, route_metric); self->mdns = mdns; self->llmnr = llmnr; return self; } + +static int +sort_captured_addresses_4 (const CList *lst_a, const CList *lst_b, gconstpointer user_data) +{ + const NMPlatformIP4Address *addr_a = NMP_OBJECT_CAST_IP4_ADDRESS (c_list_entry (lst_a, NMDedupMultiEntry, lst_entries)->obj); + const NMPlatformIP4Address *addr_b = NMP_OBJECT_CAST_IP4_ADDRESS (c_list_entry (lst_b, NMDedupMultiEntry, lst_entries)->obj); + + nm_assert (addr_a); + nm_assert (addr_b); + + /* Primary addresses first */ + return NM_FLAGS_HAS (addr_a->n_ifa_flags, IFA_F_SECONDARY) - + NM_FLAGS_HAS (addr_b->n_ifa_flags, IFA_F_SECONDARY); +} + +static int +sort_captured_addresses_6 (const CList *lst_a, const CList *lst_b, gconstpointer user_data) +{ + NMSettingIP6ConfigPrivacy ipv6_privacy_rfc4941 = GPOINTER_TO_INT (user_data); + const NMPlatformIP6Address *addr_a = NMP_OBJECT_CAST_IP6_ADDRESS (c_list_entry (lst_a, NMDedupMultiEntry, lst_entries)->obj); + const NMPlatformIP6Address *addr_b = NMP_OBJECT_CAST_IP6_ADDRESS (c_list_entry (lst_b, NMDedupMultiEntry, lst_entries)->obj); + + return nm_platform_ip6_address_pretty_sort_cmp (addr_a, + addr_b, + ipv6_privacy_rfc4941 == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR); +} + +static void +_init_from_platform (NML3ConfigData *self, + int addr_family, + NMPlatform *platform, + NMSettingIP6ConfigPrivacy ipv6_privacy_rfc4941) +{ + const gboolean IS_IPv4 = NM_IS_IPv4 (addr_family); + const NMDedupMultiHeadEntry *head_entry; + const NMPObject *plobj = NULL; + NMDedupMultiIter iter; + + nm_assert (NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert_addr_family (addr_family); + + head_entry = nm_platform_lookup_object (platform, + IS_IPv4 + ? NMP_OBJECT_TYPE_IP4_ADDRESS + : NMP_OBJECT_TYPE_IP6_ADDRESS, + self->ifindex); + if (head_entry) { + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + if (!_l3_config_data_add_obj (self->multi_idx, + &self->idx_addresses_x[IS_IPv4], + self->ifindex, + plobj, + NULL, + FALSE, + TRUE, + NULL, + NULL)) + nm_assert_not_reached (); + } + head_entry = nm_l3_config_data_lookup_addresses (self, addr_family); + nm_assert (head_entry); + nm_dedup_multi_head_entry_sort (head_entry, + IS_IPv4 + ? sort_captured_addresses_4 + : sort_captured_addresses_6, + GINT_TO_POINTER (ipv6_privacy_rfc4941)); + } + + head_entry = nm_platform_lookup_object (platform, + IS_IPv4 + ? NMP_OBJECT_TYPE_IP4_ROUTE + : NMP_OBJECT_TYPE_IP6_ROUTE, + self->ifindex); + nmp_cache_iter_for_each (&iter, head_entry, &plobj) + nm_l3_config_data_add_route (self, addr_family, plobj, NULL, NULL, NULL); +} + +NML3ConfigData * +nm_l3_config_data_new_from_platform (NMDedupMultiIndex *multi_idx, + int ifindex, + NMPlatform *platform, + NMSettingIP6ConfigPrivacy ipv6_privacy_rfc4941) +{ + + NML3ConfigData *self; + + nm_assert (NM_IS_PLATFORM (platform)); + nm_assert (ifindex > 0); + + /* Slaves have no IP configuration */ + if (nm_platform_link_get_master (platform, ifindex) > 0) + return NULL; + + self = nm_l3_config_data_new (multi_idx, ifindex); + + _init_from_platform (self, AF_INET, platform, ipv6_privacy_rfc4941); + _init_from_platform (self, AF_INET6, platform, ipv6_privacy_rfc4941); + + return self; +} + +/*****************************************************************************/ + +NML3ConfigData * +nm_l3_config_data_new_clone (const NML3ConfigData *src, + int ifindex) +{ + NML3ConfigData *self; + NMDedupMultiIter iter; + const NMPObject *obj; + + nm_assert (NM_IS_L3_CONFIG_DATA (src, TRUE)); + + /* pass 0, to use the original ifindex. You can also use this function to + * copy the configuration for a different ifindex. */ + nm_assert (ifindex >= 0); + if (ifindex <= 0) + ifindex = src->ifindex; + + self = nm_l3_config_data_new (src->multi_idx, ifindex); + + nm_l3_config_data_iter_obj_for_each (iter, src, obj, NMP_OBJECT_TYPE_IP4_ADDRESS) + nm_l3_config_data_add_address (self, AF_INET, obj, NULL, NULL); + nm_l3_config_data_iter_obj_for_each (iter, src, obj, NMP_OBJECT_TYPE_IP6_ADDRESS) + nm_l3_config_data_add_address (self, AF_INET6, obj, NULL, NULL); + nm_l3_config_data_iter_obj_for_each (iter, src, obj, NMP_OBJECT_TYPE_IP4_ROUTE) + nm_l3_config_data_add_route (self, AF_INET, obj, NULL, NULL, NULL); + nm_l3_config_data_iter_obj_for_each (iter, src, obj, NMP_OBJECT_TYPE_IP6_ROUTE) + nm_l3_config_data_add_route (self, AF_INET6, obj, NULL, NULL, NULL); + + nm_assert (self->best_default_route_4 == src->best_default_route_4); + nm_assert (self->best_default_route_6 == src->best_default_route_6); + + self->wins_4 = _garray_inaddr_clone (src->wins_4, AF_INET); + self->nameservers_4 = _garray_inaddr_clone (src->nameservers_4, AF_INET); + self->nameservers_6 = _garray_inaddr_clone (src->nameservers_6, AF_INET6); + self->domains_4 = nm_strv_ptrarray_clone (src->domains_4, TRUE); + self->domains_6 = nm_strv_ptrarray_clone (src->domains_6, TRUE); + self->searches_4 = nm_strv_ptrarray_clone (src->searches_4, TRUE); + self->searches_6 = nm_strv_ptrarray_clone (src->searches_6, TRUE); + self->dns_options_4 = nm_strv_ptrarray_clone (src->dns_options_4, TRUE); + self->dns_options_6 = nm_strv_ptrarray_clone (src->dns_options_6, TRUE); + self->dns_priority_4 = src->dns_priority_4; + self->dns_priority_6 = src->dns_priority_6; + self->mdns = src->mdns; + self->llmnr = src->llmnr; + + return self; +} diff --git a/src/nm-l3-config-data.h b/src/nm-l3-config-data.h index f7b87d7d16..5b81b57e19 100644 --- a/src/nm-l3-config-data.h +++ b/src/nm-l3-config-data.h @@ -5,22 +5,38 @@ #include "nm-glib-aux/nm-dedup-multi.h" #include "nm-setting-connection.h" +#include "nm-setting-ip6-config.h" #include "platform/nm-platform.h" +typedef enum { + NM_L3_CONFIG_DAT_FLAGS_NONE = 0, + + /* if set, then the merge flag NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES gets + * ignored during merge. */ + NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES = (1ull << 0), +} NML3ConfigDatFlags; + typedef struct _NML3ConfigData NML3ConfigData; -NML3ConfigData *nm_l3_config_data_new (NMDedupMultiIndex *multi_idx); -NML3ConfigData *nm_l3_config_data_ref (NML3ConfigData *self); -NML3ConfigData *nm_l3_config_data_ref_and_seal (NML3ConfigData *self); -NML3ConfigData *nm_l3_config_data_seal (NML3ConfigData *self); -void nm_l3_config_data_unref (NML3ConfigData *self); +NML3ConfigData *nm_l3_config_data_new (NMDedupMultiIndex *multi_idx, + int ifindex); +const NML3ConfigData *nm_l3_config_data_ref (const NML3ConfigData *self); +const NML3ConfigData *nm_l3_config_data_ref_and_seal (const NML3ConfigData *self); +const NML3ConfigData *nm_l3_config_data_seal (const NML3ConfigData *self); +void nm_l3_config_data_unref (const NML3ConfigData *self); -gboolean nm_l3_config_data_is_sealed (NML3ConfigData *self); +NM_AUTO_DEFINE_FCN0 (const NML3ConfigData *, _nm_auto_unref_l3cfg, nm_l3_config_data_unref); +#define nm_auto_unref_l3cfg nm_auto (_nm_auto_unref_l3cfg) -const NMDedupMultiHeadEntry *nm_l3_config_data_lookup_addresses (const NML3ConfigData *self, int addr_family); -const NMDedupMultiHeadEntry *nm_l3_config_data_lookup_routes (const NML3ConfigData *self, int addr_family); +NM_AUTO_DEFINE_FCN0 (NML3ConfigData *, _nm_auto_unref_l3cfg_init, nm_l3_config_data_unref); +#define nm_auto_unref_l3cfg_init nm_auto (_nm_auto_unref_l3cfg_init) -NML3ConfigData *nm_l3_config_data_new_from_connection (NMDedupMultiIndex *multi_index, +gboolean nm_l3_config_data_is_sealed (const NML3ConfigData *self); + +NML3ConfigData *nm_l3_config_data_new_clone (const NML3ConfigData *src, + int ifindex); + +NML3ConfigData *nm_l3_config_data_new_from_connection (NMDedupMultiIndex *multi_idx, int ifindex, NMConnection *connection, NMSettingConnectionMdns mdns, @@ -28,36 +44,148 @@ NML3ConfigData *nm_l3_config_data_new_from_connection (NMDedupMultiIndex *multi_ guint32 route_table, guint32 route_metric); +NML3ConfigData *nm_l3_config_data_new_from_platform (NMDedupMultiIndex *multi_idx, + int ifindex, + NMPlatform *platform, + NMSettingIP6ConfigPrivacy ipv6_privacy_rfc4941); + /*****************************************************************************/ -gboolean _nm_l3_config_data_add_address (NML3ConfigData *self, - int addr_family, - int ifindex, - const NMPObject *obj_new, - const NMPlatformIPAddress *pl_new); +const NMDedupMultiHeadEntry *nm_l3_config_data_lookup_objs (const NML3ConfigData *self, NMPObjectType obj_type); -gboolean _nm_l3_config_data_add_route (NML3ConfigData *self, +static inline const NMDedupMultiHeadEntry * +nm_l3_config_data_lookup_addresses (const NML3ConfigData *self, int addr_family) +{ + nm_assert_addr_family (addr_family); + + return nm_l3_config_data_lookup_objs (self, + addr_family == AF_INET + ? NMP_OBJECT_TYPE_IP4_ADDRESS + : NMP_OBJECT_TYPE_IP6_ADDRESS); +} + +static inline const NMDedupMultiHeadEntry * +nm_l3_config_data_lookup_routes (const NML3ConfigData *self, int addr_family) +{ + nm_assert_addr_family (addr_family); + + return nm_l3_config_data_lookup_objs (self, + addr_family == AF_INET + ? NMP_OBJECT_TYPE_IP4_ROUTE + : NMP_OBJECT_TYPE_IP6_ROUTE); +} + +#define nm_l3_config_data_iter_obj_for_each(iter, self, obj, type) \ + for (nm_dedup_multi_iter_init (&(iter), nm_l3_config_data_lookup_objs ((self), (type))); \ + nm_platform_dedup_multi_iter_next_obj (&(iter), &(obj), (type)); \ + ) + +#define nm_l3_config_data_iter_ip4_address_for_each(iter, self, address) \ + for (nm_dedup_multi_iter_init (&(iter), nm_l3_config_data_lookup_addresses ((self), AF_INET)); \ + nm_platform_dedup_multi_iter_next_ip4_address (&(iter), &(address)); \ + ) + +#define nm_l3_config_data_iter_ip6_address_for_each(iter, self, address) \ + for (nm_dedup_multi_iter_init (&(iter), nm_l3_config_data_lookup_addresses ((self), AF_INET6)); \ + nm_platform_dedup_multi_iter_next_ip6_address (&(iter), &(address)); \ + ) + +#define nm_l3_config_data_iter_ip4_route_for_each(iter, self, route) \ + for (nm_dedup_multi_iter_init (&(iter), nm_l3_config_data_lookup_routes ((self), AF_INET)); \ + nm_platform_dedup_multi_iter_next_ip4_route (&(iter), &(route)); \ + ) + +#define nm_l3_config_data_iter_ip6_route_for_each(iter, self, route) \ + for (nm_dedup_multi_iter_init (&(iter), nm_l3_config_data_lookup_routes ((self), AF_INET6)); \ + nm_platform_dedup_multi_iter_next_ip6_route (&(iter), &(route)); \ + ) + +/*****************************************************************************/ + +int nm_l3_config_data_get_ifindex (const NML3ConfigData *self); + +/*****************************************************************************/ + +NML3ConfigDatFlags nm_l3_config_data_get_flags (const NML3ConfigData *self); + +void nm_l3_config_data_set_flags_full (NML3ConfigData *self, + NML3ConfigDatFlags flags, + NML3ConfigDatFlags mask); + +static inline void +nm_l3_config_data_set_flags (NML3ConfigData *self, + NML3ConfigDatFlags flags) +{ + nm_l3_config_data_set_flags_full (self, flags, flags); +} + +static inline void +nm_l3_config_data_unset_flags (NML3ConfigData *self, + NML3ConfigDatFlags flags) +{ + nm_l3_config_data_set_flags_full (self, NM_L3_CONFIG_DAT_FLAGS_NONE, flags); +} + +/*****************************************************************************/ + +gboolean nm_l3_config_data_add_address (NML3ConfigData *self, + int addr_family, + const NMPObject *obj_new, + const NMPlatformIPAddress *pl_new, + const NMPObject **out_obj_new); + +static inline gboolean +nm_l3_config_data_add_address_4 (NML3ConfigData *self, const NMPlatformIP4Address *addr) +{ + return nm_l3_config_data_add_address (self, AF_INET, NULL, NM_PLATFORM_IP_ADDRESS_CAST (addr), NULL); +} + +static inline gboolean +nm_l3_config_data_add_address_6 (NML3ConfigData *self, const NMPlatformIP6Address *addr) +{ + return nm_l3_config_data_add_address (self, AF_INET6, NULL, NM_PLATFORM_IP_ADDRESS_CAST (addr), NULL); +} + +gboolean nm_l3_config_data_add_route (NML3ConfigData *self, + int addr_family, + const NMPObject *obj_new, + const NMPlatformIPRoute *pl_new, + const NMPObject **out_obj_new, + gboolean *out_changed_best_default_route); + +static inline gboolean +nm_l3_config_data_add_route_4 (NML3ConfigData *self, const NMPlatformIP4Route *rt) +{ + return nm_l3_config_data_add_route (self, AF_INET, NULL, NM_PLATFORM_IP_ROUTE_CAST (rt), NULL, NULL); +} + +static inline gboolean +nm_l3_config_data_add_route_6 (NML3ConfigData *self, const NMPlatformIP6Route *rt) +{ + return nm_l3_config_data_add_route (self, AF_INET6, NULL, NM_PLATFORM_IP_ROUTE_CAST (rt), NULL, NULL); +} + +gboolean nm_l3_config_data_add_nameserver (NML3ConfigData *self, + int addr_family, + gconstpointer /* (const NMIPAddr *) */ nameserver); + +gboolean nm_l3_config_data_add_wins (NML3ConfigData *self, + in_addr_t wins); + +gboolean nm_l3_config_data_add_domain (NML3ConfigData *self, int addr_family, - int ifindex, - const NMPObject *obj_new, - const NMPlatformIPRoute *pl_new, - const NMPObject **out_obj_new, - gboolean *out_changed_best_default_route); + const char *domain); -gboolean _nm_l3_config_data_add_domain (NML3ConfigData *self, - int addr_family, - const char *domain); +gboolean nm_l3_config_data_add_search (NML3ConfigData *self, + int addr_family, + const char *search); -gboolean _nm_l3_config_data_add_search (NML3ConfigData *self, - int addr_family, - const char *search); +gboolean nm_l3_config_data_add_dns_option (NML3ConfigData *self, + int addr_family, + const char *dns_option); -gboolean _nm_l3_config_data_add_dns_option (NML3ConfigData *self, - int addr_family, - const char *dns_option); - -gboolean _nm_l3_config_data_set_dns_priority (NML3ConfigData *self, - int addr_family, - int dns_priority); +gboolean nm_l3_config_data_set_dns_priority (NML3ConfigData *self, + int addr_family, + int dns_priority); #endif /* __NM_L3_CONFIG_DATA_H__ */ diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 5c4a3abb55..7b1f87f189 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -7202,6 +7202,121 @@ nm_platform_lnk_wireguard_cmp (const NMPlatformLnkWireGuard *a, const NMPlatform return 0; } +static int +_address_pretty_sort_get_prio_4 (in_addr_t addr) +{ + if (nm_utils_ip4_address_is_link_local (addr)) + return 0; + return 1; +} + +int +nm_platform_ip4_address_pretty_sort_cmp (const NMPlatformIP4Address *a1, + const NMPlatformIP4Address *a2) +{ + in_addr_t n1; + in_addr_t n2; + + nm_assert (a1); + nm_assert (a2); + + /* Sort by address type. For example link local will + * be sorted *after* a global address. */ + NM_CMP_DIRECT (_address_pretty_sort_get_prio_4 (a2->address), + _address_pretty_sort_get_prio_4 (a1->address)); + + /* Sort the addresses based on their source. */ + NM_CMP_DIRECT (a2->addr_source, a1->addr_source); + + NM_CMP_DIRECT ((a2->label[0] == '\0'), + (a1->label[0] == '\0')); + + /* Finally, sort addresses lexically. We compare only the + * network part so that the order of addresses in the same + * subnet (and thus also the primary/secondary role) is + * preserved. + */ + n1 = a1->address & _nm_utils_ip4_prefix_to_netmask (a1->plen); + n2 = a2->address & _nm_utils_ip4_prefix_to_netmask (a2->plen); + NM_CMP_DIRECT_MEMCMP (&n1, &n2, sizeof (guint32)); + return 0; +} + +static int +_address_pretty_sort_get_prio_6 (const struct in6_addr *addr) +{ + if (IN6_IS_ADDR_V4MAPPED (addr)) + return 0; + if (IN6_IS_ADDR_V4COMPAT (addr)) + return 1; + if (IN6_IS_ADDR_UNSPECIFIED (addr)) + return 2; + if (IN6_IS_ADDR_LOOPBACK (addr)) + return 3; + if (IN6_IS_ADDR_LINKLOCAL (addr)) + return 4; + if (IN6_IS_ADDR_SITELOCAL (addr)) + return 5; + return 6; +} + +int +nm_platform_ip6_address_pretty_sort_cmp (const NMPlatformIP6Address *a1, + const NMPlatformIP6Address *a2, + gboolean prefer_temp) +{ + gboolean ipv6_privacy1; + gboolean ipv6_privacy2; + + nm_assert (a1); + nm_assert (a2); + + /* tentative addresses are always sorted back... */ + /* sort tentative addresses after non-tentative. */ + NM_CMP_DIRECT (NM_FLAGS_HAS (a1->n_ifa_flags, IFA_F_TENTATIVE), + NM_FLAGS_HAS (a2->n_ifa_flags, IFA_F_TENTATIVE)); + + /* Sort by address type. For example link local will + * be sorted *after* site local or global. */ + NM_CMP_DIRECT (_address_pretty_sort_get_prio_6 (&a2->address), + _address_pretty_sort_get_prio_6 (&a1->address)); + + ipv6_privacy1 = NM_FLAGS_ANY (a1->n_ifa_flags, IFA_F_MANAGETEMPADDR | IFA_F_TEMPORARY); + ipv6_privacy2 = NM_FLAGS_ANY (a2->n_ifa_flags, IFA_F_MANAGETEMPADDR | IFA_F_TEMPORARY); + if ( ipv6_privacy1 + || ipv6_privacy2) { + gboolean public1 = TRUE; + gboolean public2 = TRUE; + + if (ipv6_privacy1) { + if (a1->n_ifa_flags & IFA_F_TEMPORARY) + public1 = prefer_temp; + else + public1 = !prefer_temp; + } + if (ipv6_privacy2) { + if (a2->n_ifa_flags & IFA_F_TEMPORARY) + public2 = prefer_temp; + else + public2 = !prefer_temp; + } + + NM_CMP_DIRECT (public2, public1); + } + + /* Sort the addresses based on their source. */ + NM_CMP_DIRECT (a2->addr_source, a1->addr_source); + + /* sort permanent addresses before non-permanent. */ + NM_CMP_DIRECT (NM_FLAGS_HAS (a2->n_ifa_flags, IFA_F_PERMANENT), + NM_FLAGS_HAS (a1->n_ifa_flags, IFA_F_PERMANENT)); + + /* finally sort addresses lexically */ + NM_CMP_DIRECT_IN6ADDR (&a1->address, &a2->address); + NM_CMP_DIRECT_MEMCMP (a1, a2, sizeof (*a1)); + return 0; +} + void nm_platform_ip4_address_hash_update (const NMPlatformIP4Address *obj, NMHashState *h) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 339ef5ba3b..1a2e339100 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -1943,6 +1943,13 @@ int nm_platform_lnk_wireguard_cmp (const NMPlatformLnkWireGuard *a, const NMPlat int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b); int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b); +int nm_platform_ip4_address_pretty_sort_cmp (const NMPlatformIP4Address *a1, + const NMPlatformIP4Address *a2); + +int nm_platform_ip6_address_pretty_sort_cmp (const NMPlatformIP6Address *a1, + const NMPlatformIP6Address *a2, + gboolean prefer_temp); + int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, NMPlatformIPRouteCmpType cmp_type); int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, NMPlatformIPRouteCmpType cmp_type); diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index dd00522064..c31548cb18 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -1057,4 +1057,63 @@ nmp_object_ip_route_is_best_defaut_route (const NMPObject *obj) && r->type_coerced == nm_platform_route_type_coerce (1 /* RTN_UNICAST */); } +/*****************************************************************************/ + +static inline gboolean +nm_platform_dedup_multi_iter_next_obj (NMDedupMultiIter *ipconf_iter, const NMPObject **out_obj, NMPObjectType assert_obj_type) +{ + gboolean has_next; + + has_next = nm_dedup_multi_iter_next (ipconf_iter); + nm_assert ( assert_obj_type == NMP_OBJECT_TYPE_UNKNOWN + || !has_next + || NMP_OBJECT_GET_TYPE (ipconf_iter->current->obj) == assert_obj_type); + NM_SET_OUT (out_obj, has_next ? ipconf_iter->current->obj : NULL); + return has_next; +} + +static inline gboolean +nm_platform_dedup_multi_iter_next_ip4_address (NMDedupMultiIter *ipconf_iter, const NMPlatformIP4Address **out_address) +{ + gboolean has_next; + + has_next = nm_dedup_multi_iter_next (ipconf_iter); + if (out_address) + *out_address = has_next ? NMP_OBJECT_CAST_IP4_ADDRESS (ipconf_iter->current->obj) : NULL; + return has_next; +} + +static inline gboolean +nm_platform_dedup_multi_iter_next_ip4_route (NMDedupMultiIter *ipconf_iter, const NMPlatformIP4Route **out_route) +{ + gboolean has_next; + + has_next = nm_dedup_multi_iter_next (ipconf_iter); + if (out_route) + *out_route = has_next ? NMP_OBJECT_CAST_IP4_ROUTE (ipconf_iter->current->obj) : NULL; + return has_next; +} + +static inline gboolean +nm_platform_dedup_multi_iter_next_ip6_address (NMDedupMultiIter *ipconf_iter, const NMPlatformIP6Address **out_address) +{ + gboolean has_next; + + has_next = nm_dedup_multi_iter_next (ipconf_iter); + if (out_address) + *out_address = has_next ? NMP_OBJECT_CAST_IP6_ADDRESS (ipconf_iter->current->obj) : NULL; + return has_next; +} + +static inline gboolean +nm_platform_dedup_multi_iter_next_ip6_route (NMDedupMultiIter *ipconf_iter, const NMPlatformIP6Route **out_route) +{ + gboolean has_next; + + has_next = nm_dedup_multi_iter_next (ipconf_iter); + if (out_route) + *out_route = has_next ? NMP_OBJECT_CAST_IP6_ROUTE (ipconf_iter->current->obj) : NULL; + return has_next; +} + #endif /* __NMP_OBJECT_H__ */ diff --git a/src/platform/tests/test-platform-general.c b/src/platform/tests/test-platform-general.c index 255210f220..86ffdbedcf 100644 --- a/src/platform/tests/test-platform-general.c +++ b/src/platform/tests/test-platform-general.c @@ -62,6 +62,651 @@ test_nm_platform_link_flags2str (void) /*****************************************************************************/ +static int +_address_pretty_sort_cmp (gconstpointer a, + gconstpointer b, + gpointer test_data) +{ + const int TEST_DATA_I = GPOINTER_TO_INT (test_data); + const int addr_family = (TEST_DATA_I == 0 ? AF_INET : AF_INET6); + const int IPV6_PREFER_TEMP = (TEST_DATA_I == 2); + const NMPlatformIPXAddress *a_a = a; + const NMPlatformIPXAddress *a_b = b; + + if (addr_family == AF_INET) + return nm_platform_ip4_address_pretty_sort_cmp (&a_a->a4, &a_b->a4); + + return nm_platform_ip6_address_pretty_sort_cmp (&a_a->a6, &a_b->a6, IPV6_PREFER_TEMP); +} + +static void +test_platform_ip_address_pretty_sort_cmp (gconstpointer test_data) +{ + static const char *const EXPECTED_BUFFER[3] = { + [0] = ( + "5b1aea34648cabfec7c3523f76cf1ce34ca17a9a32f3f0f218424e48836dd1cb504e03d53e1124c5" + "0065aeb2e6fbf952902383028e3b47f280f062ea1a7e0b7be218d067530e1b0487b8c3b99f2b8a1a" + "8982c42f0000003437c5156e072b2f2f0037c9cfe07c34ddb3980deb14ab7b5af84a034703000000" + "883b0f3fd6ed84d6c959e553b887edcd01c2f5d200000043b809d259e499db7d00f1853bdcb0e4bc" + "0e2b00b667b7b16d8d1e69c803000000b973972c17a47631c169f11ff9119c400368b6630000007a" + "034f43340d01683c0045097aea4a849f060ddf57b24a5be9636360d603000000ad7c499dd538d345" + "74c038404923e75d0209e2fc0000004acc807cdce682f80f00315c45ef817264c89a736ed55ed637" + "b96c200203000000faf1809becd2506315a6da29b2e94d3a031fe0e900000083a36035fb6297dfa7" + "00686b5efd0d53bb6215de4bb6f6f3d031a79028030000008bb836c0a25ea71f5daaed4d99eb2ebe" + "033c432f000000bf4ccf30d3aaaf02a4005d7308b67f91bf9d82c856ba942455e8d07c8403000000" + "f2abb982b001ec16901f55f960c55c22022099a80000002b4d4647f53b1921af0088e3759a08e7a5" + "6663861eea1bf42c12ea3b9503000000fb95e8332fdfff658483a2d039a7bf1402d3481e00000060" + "e89f7abdb682380a00eae374835b4a49a2b980b6aba92da6409969aa03000000e00473755d31e5b2" + "de252167c1c91b3a02ba0c700000007740318db913a353ed006efc068829c0e66ad0143a0554efb4" + "40e55b8b03000000c0cfb2b4386bec092fa5757ecde9348b00c12ebd000000ab667224dae775e5cc" + "0041aca2ff0f576767d3648102b61886d149f07403000000153ece68ade15cec25a59273e7519f34" + "c4458d70000000f3819aa46fbe1439340033ae6dec0fb124f264af67eed7c9a8ecc8fb1103000000" + "fcebbaeb0c56535923f14874042a8aff021f8e5ec3cc13cc36bbe3c9bb0ec36f00e007bb64a2827b" + "7cdd38d0314c178e5a06c40b03000000ab90135fa636af4464d210a256be75e0029c44770000004b" + "2e69220d6c0fc09c25d6534c809829af4a9df58dbfef186d416f3a1e030000002c932e655203d82a" + "3c84c4eb274ed18603780281000000f2235376239daeaacb3cae864b437baaae91921681c2162b9b" + "69e66142030000004fda8a3e0b841cf76391dd68269b53ec0244a831000000b78c54dda9ac3bb1b1" + "d43e6505621b9a7f0422ae3fc8979ee0416f95e70300000057d6249b652ba98c7dc7f17f666969e4" + "023baf7a000000ee0b06fa9e988f80f0de6dc8dfcf2a3ad3bbcc0fa3b314f695111d891d03000000" + "cd897619f51f44e644d7cf1d06b2b1150082549e62c12fba5b1cdec48d10bbb13b8313d8cd2a24d3" + "4fc812bd2f8a59d90fcc00ac030000005292cd32dc096cd5d8a4c5cf3351ee1c03c2056c00000051" + "bbce426cfa4b861cc78592be7b14e7ba9c15acb881ae55f0e5fe7d360300000066a3ae3939762df3" + "3a2d55060c78d55100b110fd00000041b9aca07b6e4925dd27943a272c171ed15abbbe1cd911db7b" + "86ed271803000000a5edc511c1507a141e0f515638c7ba31027609450000003357ae79989870ccec" + "3def0ad92749e016663fe6ee0228c1da82d1595603000000348352d715cf9d411ea012e5307294b6" + "0146dac4000000075efee38dd16f8ee4ccd2f50c30706cae3fdcc2f0ee3d5e26bb20413203000000" + "862573c2303dd1d65c7b2cffeca6d1adaccae11f0000000f855ebf3b772eb2b1c896c9a7304f6645" + "0a5f6abd850b06e3b10123e6030000001dff045298cfee0636674cdefb57b9ae54cfe8f400000038" + "1ba2c4396de60f032bc7f34de2959871c0d4c0d4eb720c4ab550c5db03000000f32f4af595d785d5" + "c1b5aad487c192f08bd7a09b00000043288cd9bf66ec305a225a0c71b2ce78bb16104c8eaf18c565" + "b16c7376030000005219061ab4c5c79489b2cc6a883c146972decb8b000000f5e6d66df46ea13910" + "7754dee62c36d2fc70ccc567df7a49b8585287dc03000000cfb18b2b2cb749e2e03e544d0eb4f73e" + "75039fcf251b32fc79685b05ddd3aa9ba511d2e40edb4d758fb554158ae5c7c0beb42b3403000000" + "895d5f24037d233302ad3b82d639272e0246eadfbd2146bf8cfdb205f90e54b58a6ee136a779f37c" + "30d2c5053c40ecaec38b6b8e03000000bea73223e59bf0193432e9fa7a899f2d8ec7e4b89bf5a5d0" + "6776e66a9d80ab132e1ac921eb76adbb229df32e561fa80a0fc4676703000000a23eb66e720da9e0" + "7ac998b5690807d50217369ee1af4ca5a6a95581af5fd7ceacdca10f47d7b351a36b178aabc78a4a" + "1a0dd8c003000000e2815a1a37a52bddd1c2f1018b587eed03bb58f0e9201f17bd99fcf72909ac9e" + "7a55299e9bb4fd53bc7417940fcffe3f81cafd6302000000d6732578acd14320aefd4503189f7630" + "038e501c0000002b9f3c39f24b0572b100745cb25851429b3bbfb50168dfd04eb62f22ca02000000" + "891715df7fc6a902edae579e2e10c7f7022ba0340436242cbeb0248cee3fbc160032d4f28aa28c08" + "f80dd50c6712dfb4abba4a32020000008ffe423d01883918039249f398f9b37ea091465100000064" + "3722d9b707c0d8a400b7c8307f06b4b29088f20d9ac676d5e4bafc4e02000000fde69eec3af2e6d0" + "bd68ab722af14548b29572e504265f6c72923e22594f3f790008ed2e2ebb0771db46a54cadb245ea" + "8c3b371502000000710c030690f5f18ea125dbf7d7e93bd6011fa56dfdcfc1155f236c8b9c79a620" + "00660bbf024b03ff0a8e27c405e64244e36f90d402000000fd41fe47684b370b6ec6584d64496089" + "570968ead4d1ae91c819bb068196d59900de3246e43f5e7945aaf95e2ffa3a119c64ed0402000000" + "a660ac824b7fae389861419c50da49bf02092583000000259f9f0251becc987907879cca68fec7bb" + "bb5f8edf248b4995d184e82002000000a19cdf6dd1c173f6078a806d329c9b0000bfc972000000f5" + "b2cd3dbddc74e26de958e48d2ab8b0313e7f8933e315130f641e447502000000b9b68c08a5e4351e" + "a349e1ccf662e058b879a45100000045fcb6a035339d504c9726d80d9c2d89df765b4d9a130257dc" + "d1e1b34902000000bcd7be07d78e6222e45aaf61814f703b40125e6b000000cbaaa37b861e6d46da" + "fe7d6ec4ac1ea051010911915ddb05f2c43bd794010000005bfe47c6f53a54e01b0c1d89414d94d0" + "032d2ec50000000103781b0f294a2b7300421398f4de67e9cee64b38b56e03e01539ce4101000000" + "18238487a417f3da01d99dae5f19009601582cab0000005b2363d13edc5aa115005eb914d8fbe9a4" + "fdb3d117d76b0de5bd82e9ea010000003d1b91caae8cb60b49ba9be338d856a40267c3d400000064" + "9da90bd2fff2f2560046870bd7d5f14870c6d18d6242b356b9ef1b2101000000f90adac616a31dc2" + "e46a234558817151008fc9c900000073e64b0bd761fdf274005dca8ce1bd1871ae17bb4515856092" + "b4d9e89b010000006855676c277cf1bd017c9148da5892bb0351c3a70000009f3391ce7d3fd48469" + "005f0c233dbdd2a97835df1f1782dee86c1de913010000003ee1d76fc1ea76e98c9dfc78997ab53e" + "00c21963f5b4cb2454830c68e44ea74b002b83f9b3bee14d861a4c9eeecc89f65408c1b701000000" + "d9e1825fa638e1af284a024b7f9e85ff00e050a2000000276e08cb887464b93400c3127c750fabdd" + "69121aec129cdc690d58fbcc01000000d0d44ff1e51c35157666c05348e6f50700a8e89800000012" + "b900b2061d0c334b009f2dd1cdf64b0f9a60e0e289f08db3fde6b0250100000039dd8f88152a5845" + "4d9ca9d20f45dfa702e78604000000fbcd7db68b9ae586da00b4070c50320427c4dd3d031e33f22c" + "210aeb09010000007000b96d06992b6a58acd3995b9663d20248f333ef467092818aa77d6732b678" + "00844ef5a943825fcd743f59bd14c89b955e1a13010000007acbce3e3bcdf3824f1b134847ff26ba" + "009a774900000017ec852d59f3d17232edd86ad6c3103a68843a9aef34983882d3d3878501000000" + "5e0dfe491d1ba96742c7b5e02b2271220188b02a06d0dc5504b0595daf37deb499996bfb667f072d" + "ec1e5d9cdc8a11f4409bcfb30100000099d90a8543961b2ccd47724a3c460ba80383f4c500000063" + "eafb1ac4c0982b283aa9986700b2a2b3ed257b8b0489f48f053ec8ca0100000027335a25a364d101" + "5ffac03089f4553902b01784000000d7b83579b8da27345a72437f9b6245de39ec9e71ee4b951507" + "f121014a01000000efc67bce716c856e3973dc42a1003be94f89d8ee0000009b5d5bbe6c10085f3d" + "6176f78a19bb8df1804c122fce5078c156e8f3fe010000000ea8042602a1f8e6f5657f3f9e3eb807" + "cbad7645000000b8df6f628a70456d79f25d5895fb57fa60d9279fb2b8fcbac65ad47b8a01000000" + "da40d88d40a6d75bc404156225b7eedefc2b44574b15e2ae496ad01bf007eacb0a28aec868282510" + "b60291ea6480e356925b568a0000000087bb24e5264fd3ebe9cf9f6df9615189018ee815000000a7" + "5c9555876b6a3f13002b6cb8360feaac1d5c302df59dd32a7a859db500000000362956cd46646a0e" + "222160e5f769bb290366ed370000005b6a813387e99bb834009da86c64fefab2548759d313a5b92d" + "8e47935e0000000034f0386a253c21d94064f6b021281e230094ae20000000d71fd050bf8d85055b" + "00e3756ccdb3455c60ca7b11c66af76e594f24a100000000e143fd52599364e13468f80fd514573f" + "b572671c0000006932d1d5f5d0ce2cf6007a70ba5193a162bc92ec1b11d9172c857ae81200000000" + "3e29535402e9b690c628d048eacce745ea213cb1000000b632ef3be6070dafa200187470e9da5570" + "9427c226d324d9a08487fd0d00000000b7a350f9fc1519defa7db4532545666937c22a3b000000dc" + "c405cbee5016c25200d8901d7a0165fe20744edb6ba04f14a4c73cf500000000a4bab14874afdf54" + "e6aae816430607ca0675e09818e9bbec5918c59068baf76a008940f6fc3bbdc7f6090f756aae660b" + "6e4c699300000000d9c1e67743efb54e54270e46042e911803894e38000000376feecb80ac245409" + "c0becc271d9c2f67179bff0644399ae7e3c9472e00000000c5cfd9f2343b21362c19a0921dce2f83" + "00defa45000000270b9977e166bee737fe73670c439a644c323b59b4cd20eb7dabea74f700000000" + "f6989d2d6a909e986ff7add5df2c93e05459507b0000000f466554d2ae4d52a8c67b2e48b47003c8" + "1785d3ffdbd9a617df6b3542000000004c5cf8107ba282f4f983821918f93e742d08f0550000006f" + "2292362e5d68265d9f98c82d9b7a559be3acf4fc36fa6b5159747cf200000000ab2dadc5a39411fd" + "4ff1116d478987316a553fc2000000cfc6ebe434a7ae8ff040483e310819e3b10db116431ec6f769" + "438a72e1000000002495a609675344f7e2e3a5ebaec3c85f0a1742f70abe95c50345132a61eda239" + "d9d083c3bf085387046ef8a36f0e9e696b382ab0000000009a6ce5d906837dbca6a5ee19d6f63fe9" + "03dd01f7246f13b2050424a2b3a45ef7a029c896b4132bd895072cfeffe9d6815997069500000000" + "0d3c723b91adb0da7c4aa7e7eb5a15bc03015fb98b841fd84cc43c510385b9a4c2aac1d67a909b29" + "7c703915312e9c3cae02dfa000000000dd603bd35e7fa0f02f2f3313d8469d09a92409c0b7f0318a" + "575a4f8e061db3dd7fde25654a4059d565dbc8a91e3b4457b077ddad3108be69f9b97d05c917ad6b" + "10e693bb6e26f2ba90c8e909a9fe20e5c7a4c656482a9b0d00625009a40aeb62a42b6a62548e3c38" + "cd3c72f203000000ca82ac5180101be4f85cef468ea086ea01aafdc3a9fe1ec787bc45db7c52a52d" + "00bd39a44e8e8bc17c01ac63eca0c1cf5ff7f03a03000000c9a89192c1c8be55281a59d1fd338f35" + "0075f8cea9fec34573654ea6624f138ef9531cd9367a02e4d241989477a363d53b02239e03000000" + "24438387def0f4c6544e4b275d9b714600f810d2a9fec17647176b7c07d856e3b883efebc09dd9d6" + "1966b7ae7412041d57393c6f03000000182c0287822a272bec4501a1e27acfee018588ffa9fe6cae" + "426de59560fad65d67c624f285d7174177a47579dda0b6eaa9a84c820300000070b1646d8026e9f1" + "704f1b16286ba2da017ef082a9feed33ef60a8b540b26f66761d1f13badfad0fe8fa8f3c1aad2a82" + "fa40546c03000000df2d7c2790d3119a051bb2ee8192ac0cfa3abc1ea9fe3e7d75a2f42b50c6a363" + "40132378b95c59313bacba64dbe996206e6904f50200000047150b9b14010469823acb72bb89182f" + "00112196a9feb9153b36bc60be5b534e006527f67485ab35aca0c7ee419733853cf09e8b02000000" + "e79c10acfce165e332a62384ec04e5ba009185ada9fe0070a36dd51323b2c54200154d12f86c260a" + "9edfa7a74c1c83c1050f63f802000000443cacf59c6379a44b7892f487afa98c0221c19ca9fe942f" + "460bcea75481f25e007d0de9a7afe283bd2f22ead05ff72006c83bc0020000004bdade862c224f6f" + "36506ebd455e679c00369bb8a9fecec3f8c8fa6867a982be8a934f852cc3d4d82bc0ec7303f99f8f" + "def85b7502000000a0bef8675b29a197b7b3cceaf5f1bb120335256aa9fe6e5d58099ffc4a503a71" + "2350acbd48411f0dc15d2f0f49dad345d966279502000000e06302aba042aaa218dc091e9aa1477f" + "6fdc9830a9fec95829a8838314dff34d24c332219a1b163a732d803e0e2f4f916d06412601000000" + "98c39e7cc282208fefc57ff447036b9501adcb22a9fe793f797a3c7dadd1c86e009d0c90bc512e13" + "7dcef5e4a27985bd5cfd5ce601000000152f2b70eaef7443e0f79ab6902dde5301b3ec71a9fe9f25" + "4ac95883195580410062ed564153e17478f8c3344d89c0bbfaa100fd01000000be184524a6bdc878" + "9cf851782d895bcc03a98489a9fe8c1287e6f7bb020ffdb00012098610e52bb2a16a4008aefd545b" + "0d80684e01000000ba8110fb9733cc24904f288262e6ea77032fa5f8a9feeefa701d120523bd98f2" + "00098b43cd68be6e3f81268193fd637e9037d7a701000000c47cf0f551e96770a754ac19ef820fe0" + "0031f2d3a9fe049150b8d10ab700cc3a7cf51be0403b654ba2f56808092069af5f5b481b01000000" + "68cb3bc873b04d937a6ed8f7bc51e54066fed098a9fe048a92d3adc69a84eb47622400207799416a" + "f1f0a086fbd7e2f7dea0077a00000000c386e9c6e6a2cbfa10ee58bdc75183600085d627a9feb1cb" + "e491cbbbf9443fd6007eb3c5bf64b671d6f18dbf463f9b83f512dc1c00000000fbab244735d67c61" + "283031667b2d74a102e0b1b1a9fe2aa590a2312e17f1a35900459582f4ef43c780908872746e39ef" + "a9a89f8700000000fcdf6d9be94030b34774d1d7dddedd9802f0f627a9fe965a87041331b2834bcf" + "00b4e3ce848518c4e3f6cbf25e5e1b992231bb0200000000173c333cd03bc905b7b899afeb760e3f" + "024a2efca9fe96b89b1bc8f415bd4e77be46bae5a1b3cae76665a268abfe8a41a84e27c100000000" + "cb29efdf672d2fa57fc85ebbe276c5660364192da9fee7af5eb888e9eb37bb046686943b101e1f55" + "3215abf8fbdf17c3677e5a3a00000000608df061d45d864d09f4ecf17625f82d03c74828a9fe1e37" + "1051852c972ea7954079884af257b044fd13a6826a4c619f3d136cac000000009402a4c216772167" + "3f2b02b3256ead1f03ea9bc1a9fefca162fb81e733cff620ca7feefe1933631e8e69f6d9d6962d2c" + ), + [1] = ( + "54270e46020000006a894e387625da376feecb80ac245409c0becc271d9c2f67179bff0644399ae7" + "9c64ed0432d599eaa660ac824b7fae389861419c7a899f2d010000009bf5a5d06776e66a9d80ab13" + "2e1ac921eb76adbb229df32e561fa80a40e55b8b1dd92e18c0cfb2b4386bec092fa5757ecde9348b" + "c4e1966800000000b3121cd5ef51e696c816290dbaee0e7726d082e1530ff5397c9125f59577d71c" + "4b258a005116d11354edff62ceaa458fc75a91c425a5927300000000c4458d70911714f1819aa46f" + "be143934c933ae6dec0fb124f264af67eed7c9a8c38b6b8ee2614344bea73223e59bf0193432e9fa" + "4cc43c5103000000c2aac1d67a909b297c703915312e9c3c5a06c40b20ea99d5ab90135fa636af44" + "64d210a256be75e0509c4477d19ac64b2e69220d12ea3b9501000000fb95e8332fdfff658483a2d0" + "39a7bf148ed3481e0bccc460e89f7abdb682380a62eae374835b4a49a2b980b6aba92da6409969aa" + "288cd9bf00000000225a0c71b2ce78bb16104c8eaf18c565ecc8fb112087b97cfcebbaeb0c565359" + "23f14874042a8aff1d1f8e5ec3cc13cc36bbe3c9bb0ec36f0000000064a2827b7cdd38d0314c178e" + "925b568ae56bc4e9fefb24e5264fd3ebe9cf9f6df9615189f78ee815b2781ea55c9555876b6a3f13" + "02e9b69000000000eacce745ea213cb1a84035b632ef3be6070dafa2fed87470e9da55709427c226" + "d324d9a086ed27184b443181a5edc511c1507a142fea9bc10300000062fb81e733cff620ca7feefe" + "1933631e8e69f6d9fed62d2c6e6904f57239c09c47150b9b14010469823acb72bb89182f93112196" + "9985d62700000000e491cbbbf9443fd6a77eb3c5bf64b671d6f18dbffeff9b8306c83bc026977911" + "4bdade862c224f6f36506ebd455e679cef369bb8d514573f03000000f6932f6932d1d5f5d0ce2cf6" + "bf7a70ba5193a162fe92ec1b11d9172cf84a03478b82cdd8883b0f3fd6ed84d6c959e553b887edcd" + "6297dfa700000000fd0d53bb6215de4bb6f6f3d031a790287e45e9c1feb836c0a25ea71f5daaed4d" + "99eb2ebebe3c432fec7d3abc4ccf30d3aaaf02a41e0f515601000000f57609453df7803357ae7998" + "9870ccec3def0ad9000000000000000000000000000000019f05a16768cb3bc873b04d937a6ed8f7" + "ae8cb60b0300000038d856a40c67c3d4afa9c8649da90bd2fff2f256000000000000000000000000" + "00000001955e1a13d1111b067acbce3e3bcdf38200154d12010000009edfa7a74c1c83c18e47935e" + "8354846e34f0386a00000000000000000000000000000001ac26c7d41fd050bf8d85055bcfe3756c" + "a2f56808092069affaa100fdfdd68d34be184524a6bdc8789cf85178000000000000000000000000" + "00000000020ffdb0e612098610e52bb2a16a40086f0e9e6903000000ec2e2924348352d715cf9d41" + "1ea012e5307294b600000000000000000000000000000000ccd2f50c30706cae3fdcc2f0ee3d5e26" + "81ae55f0030000000aa20624fbab244735d67c61283031667b2d74a1000000000000000000000000" + "0000000000459582f4ef43c780908872746e39efaefd545b020000007ced4f8b362956cd46646a0e" + "222160e5f769bb2900000000000000000000000000000000a19da86c64fefab2548759d313a5b92d" + "f05d7308020000009d82c856ba942455050f63f8282f3464443cacf5000000000000000000000000" + "0000000069d9942f460bcea75481f25e307d0de96e91b91501000000be5b534e0a6527f67485ab35" + "aca0c7ee4197338500000000000000000000000000000000aefd4503189f7630248e501c9052c22b" + "5d68265d010000009b7a559be3acf4fc36fa6b513cf09e8b99289462000000000000000000000000" + "00000000b49185ad9b7d0070a36dd51323b2c542e5fe7d360100000066a3ae3939762df33a2d5506" + "0c78d551cbb110fd000000000000000000000000000000002c171ed15abbbe1cd911db7b56e8f3fe" + "9a6ce5d900000000a6a5ee19d6f63fe9cbdd01f7246f13b2050424a2000000000000000000000000" + "00000000ffe9d6812231bb02f922259b173c333cbae87d60000000005d31e5b2de252167c1c91b3a" + "36ba0c700ee78477000000000000000000000000000000006ad0143a0554efb46b382ab0404cdf02" + "7c52a52d030000004e8e8bc17c01ac63eca0c1cfbb204132fb7213e4000000000000000000000000" + "00000000accae11f8045a80f855ebf3b772eb2b1d03bc90503000000eb760e3f004a2efc8ffc96b8" + "9b1bc8f415bd4e7700000000000000000000000000000000d149f074a378b881153ece68ade15cec" + "7666c05303000000ffa8e89871fb9510b900b2061d0c334b819f2dd1000000000000000000000000" + "00000000095a3230fde69eec3af2e6d0bd68ab7210613fc90200000016a31dc2e46a234558817151" + "b38fc9c909cf8d7100000000000000000000000000000000ae17bb4515856092b4d9e89b676761b2" + "57d6249b020000007dc7f17f666969e45c3baf7a119a65ee0b06fa9e000000000000000000000000" + "00000000b314f695bd82e9ea8891ed0a3d1b91cab56e03e0010000002f70249eefc67bce716c856e" + "3973dc42a1003be9000000000000000000000000000000006176f78a19bb8df1804c122fce5078c1" + "eecc89f601000000d635edea8ffe423d01883918039249f398f9b37e000000000000000000000000" + "000000001fb7c8307f06b4b29088f20d9ac676d5f90e54b501000000a779f37c30d2c5053c40ecae" + "210aeb0934cb2a2400000000000000000000000000000000df48f333ef467092818aa77d6732b678" + "bcd7be0700000000e45aaf61814f703b40125e6baf4648cbaaa37b86000000000000000000000000" + "000000005ddb05f2a84e27c18a06e2c9cb29efdf50da49bf00000000d94beb259f9f0251becc9879" + "07879cca68fec7bb000000000000000000000000000000009402a4c2167721673f2b02b3256ead1f" + "a349e1cc00000000b879a45176740744fcb6a035339d504c9726d80d000000000000000000000000" + "000000009518862bc9a89192c1c8be55281a59d1ebfdcec30000000067a982be8a934f852cc3d4d8" + "2bc0ec7303f99f8f00000000000000000000000000000000901f55f960c55c22f32099a8020bea2a" + "5b1aea3401000000c7c3523f76cf1ce34ca17a9a32f3f0f218424e48000000000000000000000000" + "00000002e6fbf952902383028e3b47f2111d891d536c75bb01000000720da9e07ac998b5690807d5" + "2617369ee1af4ca500000000000000000000ffff47d7b351a36b178aabc78a4a0d80684ee5dbf45b" + "17a4763102000000f9119c40b468b66331bca67a034f43340d01683c00000000000000000000ffff" + "b24a5be9b10123e6e4f15ecd1dff045298cfee069c88b02a0300000004b0595daf37deb499996bfb" + "667f072dec1e5d9cdc8a11f4409bcfb3c167090e99d90a8543961b2ccd47724a3c460ba85183f4c5" + "a7afe28302000000d05ff720b16c73761a3fcb675219061ab4c5c79489b2cc6a883c146972decb8b" + "5adac8f5e6d66df46ea139107754dee62c36d2fcc7a4c65601000000cd625009a40aeb62a42b6a62" + "548e3c38b96c20022753c5fbfaf1809becd2506315a6da29b2e94d3ab51fe0e9af98b180a36035fb" + "e36f90d401000000fd41fe47684b370b6ec6584d64496089570968ead4d1ae91c819bb068196d599" + "efde3246e43f5e7945aaf95e2ffa3a11b9ef1b21cdb3455c00000000c66af76e80f062ea1a7e0b7b" + "e218d067530e1b0487b8c3b99f2b8a1a8982c42f53700a3437c5156e072b2f2fb337c9cfe07c34dd" + "c896c9a7000000000a5f6abd850b06e3d9662795ce2cc1cee06302aba042aaa218dc091e9aa1477f" + "6fdc9830d7fbc95829a8838314dff34d24c332214d4647f5000000000f88e3759a08e7a56663861e" + "ea1bf42ccd3c72f2ad063857ca82ac5180101be4f85cef468ea086ea9aaafdc388811ec787bc45db" + "7625ca4a00000000e682f80f94315c45ef817264c89a736ed55ed637b077ddad3108be69f9b97d05" + "c917ad6b10e693bb6e26f2ba90c8e909e85e20e5b0916e5d030000004a503a712350acbd48411f0d" + "c15d2f0f49dad345599706954d2471f00d3c723b91adb0da7c4aa7e7eb5a15bcde015fb98b841fd8" + "ba8110fb03000000904f288262e6ea77a22fa5f863eaeefa701d120523bd98f29b098b43cd68be6e" + "3f81268193fd637e585287dc6ca972a2cfb18b2b3cae864b0200000091921681c2162b9bfa40546c" + "db544e44df2d7c2790d3119a051bb2ee8192ac0cfa3abc1ea0ab3e7d75a2f42b50c6a36340132378" + "8c3b371502000000710c030690f5f18ea125dbf7d7e93bd65c1fa56dfdcfc1155f236c8b9c79a620" + "5f660bbf024b03ff0a8e27c405e6424457393c6fdac12ebd01000000667224dae775e5ccd141aca2" + "ff0f576767d3648102b61886b62f22ca33478e1f891715df7fc6a902edae579e2e10c7f7a22ba034" + "abf85f0c0100000008d33a2ea67776d7f88d69c8c7e3b2d3c93ef054e93f8120abb42316c533d9c9" + "4d88189c471a1ff2f0ce3ff66e782110125ae2eddaae7d6300000000c0982b283aa9986700b2a2b3" + "ed257b8b0489f48f053ec8cac72105b327335a25a364d1015ffac03089f45539e1b0178462156cd6" + "6855676c00000000017c9148da5892bb4951c3a7ed55689d3391ce7d3fd48469845f0c233dbdd2a9" + "7835df1f1782dee88487fd0db5971b46b7a350f998c39e7c00000000efc57ff447036b9551adcb22" + "fd50793f797a3c7dadd1c86e759d0c90bc512e137dcef5e4a27985bd8d1e69c83dc21056b973972c" + "bc51e540030000006c3d048a92d3adc69a84eb47622400207799416afef0a086fbd7e2f7dea0077a" + "e9c0c0d9c386e9c6e6a2cbfa10ee58bdc75183600422ae3f03000000c43bd794c697895e5bfe47c6" + "f53a54e01b0c1d89fecd94d0e02d2ec587fc330003781b0f294a2b73c4421398f4de67e9cee64b38" + "69121aec010000000fcc00ac2daa755e5292cd32dc096cd5d8a4c5cffe91ee1cfcc2056cc1ff8e51" + "bbce426cfa4b861cc78592be7b14e7ba9c15acb836674cde0200000054cfe8f42bf0e9381ba2c439" + "6de60f032bc7f34dfe959871c0d4c0d4eb720c4ae3c9472e5f2da5d9c5cfd9f2343b21362c19a092" + "b2cd3dbd01000000e958e48d2ab8b0313e7f8933e315130fa9a84c82feb83f6e70b1646d8026e9f1" + "704f1b16286ba2dabc7ef0820c91ed33ef60a8b5bcfe97e1000000007ad742d3d7320a4f880cf47f" + "5dd0cf69cb22840ffeb3fe7749509cb6752b2cee30b7e7736a0afc9879ea40e69710fc9f6e8e99cd" + "1dce2f83020000003a3efc240b9977e166bee737fe73670c439a644c000000000000000000000000" + "000000015e0dfe491d1ba96742c7b5e02b227122cf844ef501000000cd743f59bd14c89b5cfd5ce6" + "e82e7854152f2b700000000000000000000000000000000127e19f254ac9588319558041fc62ed56" + "b83579b80300000072437f9b6245de39ec9e71ee4b951507beb42b34000000000000000000000000" + "00000001d639272e4a46eadfbd2146bf8cfdb205b3980deb020000006c1de913df1424ce3ee1d76f" + "c1ea76e98c9dfc7800000000000000000000000000000001e44ea74b4f2b83f9b3bee14d861a4c9e" + "0436242c03000000ee3fbc164632d4f28aa28c08f80dd50c6712dfb4000000000000000000000000" + "00000000078a806d329c9b008bbfc9723107f3f52af145480300000004265f6c72923e22594f3f79" + "e208ed2e2ebb07710000000000000000000000000000000039dd8f88152a58454d9ca9d20f45dfa7" + "922b6cb8030000001d5c302df59dd32a677e5a3af4fe297f608df061000000000000000000000000" + "000000008ae21e371051852c972ea7954079884a9a1b163a030000000e2f4f911a0dd8c052ed6b13" + "e2815a1a37a52bdd00000000000000000000000000000000bd99fcf72909ac9e7a55299e9bb4fd53" + "9f3c2c8803000000f51f44e644d7cf1d06b2b115d882549e62c12fba000000000000000000000000" + "000000004fc812bd2f8a59d96d064126666befbbf257b044030000006a4c619f9037d7a754655354" + "c47cf0f551e967700000000000000000000000000000000050b8d10ab700cc3a7cf51be0403b654b" + "74e7860402000000cd7db68b9ae586dacdb4070c50320427c4dd3d03000000000000000000000000" + "00000000d538d34574c038404923e75d0e09e2fcfc1519de010000002545666937c22a3b6e9686dc" + "c405cbee5016c252000000000000000000000000000000006e4c699341b95f41d9c1e67743efb54e" + "6aae660b01000000fc1fb23d24438387def0f4c6544e4b275d9b7146000000000000000000000000" + "00000000b883efebc09dd9d61966b7ae7412041dd7ac5f9901000000822a272bec4501a1e27acfee" + "7a8588ffd5a06cae0000000000000000000000000000000077a47579dda0b6ead1e1b34901eaedd5" + "61c2f5d200000000b809d259e499db7dc8f1853bdcb0e4bc0e2b00b6000000000000000000000000" + "000000005e7fa0f02f2f3313d8469d09a92409c0b4d54acb00000000a417f3da01d99dae5f190096" + "cc582cabd5ddd15a00000000000000000000000000000000fdb3d117d76b0de5416f95e7bb75d72f" + "fc2b445700000000496ad01bf007eacb0a28aec868282510b60291ea000000000000000000000000" + "000000005b29a197b7b3cceaf5f1bb12c535256a74993ade03000000e62112898dab2dade2ab2fc9" + "c56a7c86be5f962200000000000000000000000000000000bdd06352cb2c354434819f4b248eb2b8" + "dc335c8b030000000a3c8e7c91bf821c4b09cee3c37ff4283a631480000000000000000000000000" + "000000005588456e4ead7cbda620a3abae816e34e3ff1a5f03000000b4425486c619147eb0216050" + "ed7afd741024e83600000000000000000000000000000000f493472201e48d163106cc397446a33f" + "bc74179403000000438a72e12ae0436a2495a609675344f7e2e3a5eb000000000000000000000000" + "0000000061eda239d9d083c3bf085387046ef8a34153e174020000004d89c0bb5408c1b7d17fb084" + "d9e1825fa638e1af000000000000000000000000000000006e08cb887464b9344ec3127c750fabdd" + "6c0fc09c02000000809829af4a9df58dbfef186d416f3a1ef170d10f000000000000000000000000" + "0000000087780281d47a32f2235376239daeaacba9a89f8701000000fcdf6d9be94030b34774d1d7" + "dddedd9899f0f62700000000000000000000000000000000848518c4e3f6cbf25e5e1b990fc46767" + "fd338f35010000006e8cc34573654ea6624f138ef9531cd9367a02e4000000000000000000000000" + "00000000da40d88d40a6d75bc404156225b7eede2cb749e2010000000eb4f73e75039fcf251b32fc" + "79685b05ddd3aa9b000000000000000000000000000000000d58fbcc58fc4c2fd0d44ff1e51c3515" + "b7f0318a01000000061db3dd7fde25654a4059d565dbc8a91e3b4457000000000000000000000000" + "00000000c1b5aad487c192f08bd7a09bdd21444359747cf200000000ab2dadc5a39411fd4ff1116d" + "478987316a553fc2000000000000000000000000000000000819e3b10db116431ec6f7691539ce41" + "b95c593100000000dbe9962069e66142e22753344fda8a3e0b841cf7000000000000000000000000" + "000000008c54dda9ac3bb1b1d43e6505621b9a7f672d2fa501000000e276c5661a64192db44ce7af" + "5eb888e9eb37bb0400000000000000000000000000000002641e447514ca565fb9b68c08a5e4351e" + "9f3c39f201000000de745cb25851429b3bbfb50168dfd04edf6b3542000000000000000000000000" + "0000000218f93e742d08f0550b55726f2292362e70ccc56700000000a4c73cf5ffa4ffc8a4bab148" + "74afdf54e6aae8160000000000000000000000000000000268baf76ab08940f6fc3bbdc7f6090f75" + "4f1b134803000000449a774929e86716ec852d59f3d17232edd86ad6000000000000000000000000" + "000000027dba1ee7e143fd52599364e13468f80f40b26f6603000000badfad0fe8fa8f3c1aad2a82" + "530b7447d9c2f401000000000000000000000000000000028147507e1cd59ea1ae6da48b1eba6d16" + "dedea2030100000002a1f8e6f5657f3f9e3eb807cbad76451055edb8000000000000000000000000" + "00000002d9279fb2b8fcbac6abea74f7a6df7979f6989d2d000000006ff7add5df2c93e05459507b" + "5d8c6a0f466554d200000000000000000000ffff1785d3ffdbd9a617857ae8126b028c0e3e295354" + ), + [2] = ( + "4cc43c5103000000c2aac1d67a909b297c703915312e9c3c5a06c40b20ea99d5ab90135fa636af44" + "64d210a256be75e0509c4477d19ac64b2e69220d54270e46020000006a894e387625da376feecb80" + "ac245409c0becc271d9c2f67179bff0644399ae79c64ed0432d599eaa660ac824b7fae389861419c" + "12ea3b9501000000fb95e8332fdfff658483a2d039a7bf148ed3481e0bccc460e89f7abdb682380a" + "62eae374835b4a49a2b980b6aba92da6409969aa7a899f2d010000009bf5a5d06776e66a9d80ab13" + "2e1ac921eb76adbb229df32e561fa80a40e55b8b1dd92e18c0cfb2b4386bec092fa5757ecde9348b" + "288cd9bf00000000225a0c71b2ce78bb16104c8eaf18c565ecc8fb112087b97cfcebbaeb0c565359" + "23f14874042a8aff1d1f8e5ec3cc13cc36bbe3c9c4e1966800000000b3121cd5ef51e696c816290d" + "baee0e7726d082e1530ff5397c9125f59577d71c4b258a005116d11354edff62ceaa458fc75a91c4" + "25a5927300000000c4458d70911714f1819aa46fbe143934c933ae6dec0fb124f264af67eed7c9a8" + "c38b6b8ee2614344bea73223e59bf0193432e9fa2fea9bc10300000062fb81e733cff620ca7feefe" + "1933631e8e69f6d9fed62d2c6e6904f57239c09c47150b9b14010469823acb72bb89182f93112196" + "9985d62700000000e491cbbbf9443fd6a77eb3c5bf64b671d6f18dbffeff9b8306c83bc026977911" + "4bdade862c224f6f36506ebd455e679cef369bb8bb0ec36f0000000064a2827b7cdd38d0314c178e" + "925b568ae56bc4e9fefb24e5264fd3ebe9cf9f6df9615189f78ee815b2781ea55c9555876b6a3f13" + "02e9b69000000000eacce745ea213cb1a84035b632ef3be6070dafa2fed87470e9da55709427c226" + "d324d9a086ed27184b443181a5edc511c1507a14d514573f03000000f6932f6932d1d5f5d0ce2cf6" + "bf7a70ba5193a162fe92ec1b11d9172cf84a03478b82cdd8883b0f3fd6ed84d6c959e553b887edcd" + "6297dfa700000000fd0d53bb6215de4bb6f6f3d031a790287e45e9c1feb836c0a25ea71f5daaed4d" + "99eb2ebebe3c432fec7d3abc4ccf30d3aaaf02a4ae8cb60b0300000038d856a40c67c3d4afa9c864" + "9da90bd2fff2f25600000000000000000000000000000001955e1a13d1111b067acbce3e3bcdf382" + "00154d12010000009edfa7a74c1c83c18e47935e8354846e34f0386a000000000000000000000000" + "00000001ac26c7d41fd050bf8d85055bcfe3756c1e0f515601000000f57609453df7803357ae7998" + "9870ccec3def0ad9000000000000000000000000000000019f05a16768cb3bc873b04d937a6ed8f7" + "7c52a52d030000004e8e8bc17c01ac63eca0c1cfbb204132fb7213e4000000000000000000000000" + "00000000accae11f8045a80f855ebf3b772eb2b1d03bc90503000000eb760e3f004a2efc8ffc96b8" + "9b1bc8f415bd4e7700000000000000000000000000000000d149f074a378b881153ece68ade15cec" + "6f0e9e6903000000ec2e2924348352d715cf9d411ea012e5307294b6000000000000000000000000" + "00000000ccd2f50c30706cae3fdcc2f0ee3d5e267666c05303000000ffa8e89871fb9510b900b206" + "1d0c334b819f2dd100000000000000000000000000000000095a3230fde69eec3af2e6d0bd68ab72" + "81ae55f0030000000aa20624fbab244735d67c61283031667b2d74a1000000000000000000000000" + "0000000000459582f4ef43c780908872746e39ef10613fc90200000016a31dc2e46a234558817151" + "b38fc9c909cf8d7100000000000000000000000000000000ae17bb4515856092b4d9e89b676761b2" + "57d6249b020000007dc7f17f666969e45c3baf7a119a65ee0b06fa9e000000000000000000000000" + "00000000b314f695bd82e9ea8891ed0a3d1b91ca6e91b91501000000be5b534e0a6527f67485ab35" + "aca0c7ee4197338500000000000000000000000000000000aefd4503189f7630248e501c9052c22b" + "5d68265d010000009b7a559be3acf4fc36fa6b513cf09e8b99289462000000000000000000000000" + "00000000b49185ad9b7d0070a36dd51323b2c542b56e03e0010000002f70249eefc67bce716c856e" + "3973dc42a1003be9000000000000000000000000000000006176f78a19bb8df1804c122fce5078c1" + "e5fe7d360100000066a3ae3939762df33a2d55060c78d551cbb110fd000000000000000000000000" + "000000002c171ed15abbbe1cd911db7b56e8f3feeecc89f601000000d635edea8ffe423d01883918" + "039249f398f9b37e000000000000000000000000000000001fb7c8307f06b4b29088f20d9ac676d5" + "f90e54b501000000a779f37c30d2c5053c40ecae210aeb0934cb2a24000000000000000000000000" + "00000000df48f333ef467092818aa77d6732b678bcd7be0700000000e45aaf61814f703b40125e6b" + "af4648cbaaa37b86000000000000000000000000000000005ddb05f2a84e27c18a06e2c9cb29efdf" + "50da49bf00000000d94beb259f9f0251becc987907879cca68fec7bb000000000000000000000000" + "000000009402a4c2167721673f2b02b3256ead1fa349e1cc00000000b879a45176740744fcb6a035" + "339d504c9726d80d000000000000000000000000000000009518862bc9a89192c1c8be55281a59d1" + "bae87d60000000005d31e5b2de252167c1c91b3a36ba0c700ee78477000000000000000000000000" + "000000006ad0143a0554efb46b382ab0404cdf02ebfdcec30000000067a982be8a934f852cc3d4d8" + "2bc0ec7303f99f8f00000000000000000000000000000000901f55f960c55c22f32099a8020bea2a" + "a2f56808092069affaa100fdfdd68d34be184524a6bdc8789cf85178000000000000000000000000" + "00000000020ffdb0e612098610e52bb2a16a4008aefd545b020000007ced4f8b362956cd46646a0e" + "222160e5f769bb2900000000000000000000000000000000a19da86c64fefab2548759d313a5b92d" + "f05d7308020000009d82c856ba942455050f63f8282f3464443cacf5000000000000000000000000" + "0000000069d9942f460bcea75481f25e307d0de99a6ce5d900000000a6a5ee19d6f63fe9cbdd01f7" + "246f13b2050424a200000000000000000000000000000000ffe9d6812231bb02f922259b173c333c" + "5b1aea3401000000c7c3523f76cf1ce34ca17a9a32f3f0f218424e48000000000000000000000000" + "00000002e6fbf952902383028e3b47f2111d891d17a4763102000000f9119c40b468b66331bca67a" + "034f43340d01683c00000000000000000000ffffb24a5be9b10123e6e4f15ecd1dff045298cfee06" + "536c75bb01000000720da9e07ac998b5690807d52617369ee1af4ca500000000000000000000ffff" + "47d7b351a36b178aabc78a4a0d80684ee5dbf45bb0916e5d030000004a503a712350acbd48411f0d" + "c15d2f0f49dad345599706954d2471f00d3c723b91adb0da7c4aa7e7eb5a15bcde015fb98b841fd8" + "ba8110fb03000000904f288262e6ea77a22fa5f863eaeefa701d120523bd98f29b098b43cd68be6e" + "3f81268193fd637e585287dc6ca972a2cfb18b2b3cae864b0200000091921681c2162b9bfa40546c" + "db544e44df2d7c2790d3119a051bb2ee8192ac0cfa3abc1ea0ab3e7d75a2f42b50c6a36340132378" + "8c3b371502000000710c030690f5f18ea125dbf7d7e93bd65c1fa56dfdcfc1155f236c8b9c79a620" + "5f660bbf024b03ff0a8e27c405e6424457393c6fdac12ebd01000000667224dae775e5ccd141aca2" + "ff0f576767d3648102b61886b62f22ca33478e1f891715df7fc6a902edae579e2e10c7f7a22ba034" + "abf85f0c0100000008d33a2ea67776d7f88d69c8c7e3b2d3c93ef054e93f8120abb42316c533d9c9" + "4d88189c471a1ff2f0ce3ff66e782110125ae2edc7a4c65601000000cd625009a40aeb62a42b6a62" + "548e3c38b96c20022753c5fbfaf1809becd2506315a6da29b2e94d3ab51fe0e9af98b180a36035fb" + "daae7d6300000000c0982b283aa9986700b2a2b3ed257b8b0489f48f053ec8cac72105b327335a25" + "a364d1015ffac03089f45539e1b0178462156cd66855676c00000000017c9148da5892bb4951c3a7" + "ed55689d3391ce7d3fd48469845f0c233dbdd2a97835df1f1782dee88487fd0db5971b46b7a350f9" + "cdb3455c00000000c66af76e80f062ea1a7e0b7be218d067530e1b0487b8c3b99f2b8a1a8982c42f" + "53700a3437c5156e072b2f2fb337c9cfe07c34ddc896c9a7000000000a5f6abd850b06e3d9662795" + "ce2cc1cee06302aba042aaa218dc091e9aa1477f6fdc9830d7fbc95829a8838314dff34d24c33221" + "98c39e7c00000000efc57ff447036b9551adcb22fd50793f797a3c7dadd1c86e759d0c90bc512e13" + "7dcef5e4a27985bd8d1e69c83dc21056b973972c7625ca4a00000000e682f80f94315c45ef817264" + "c89a736ed55ed637b077ddad3108be69f9b97d05c917ad6b10e693bb6e26f2ba90c8e909e85e20e5" + "9c88b02a0300000004b0595daf37deb499996bfb667f072dec1e5d9cdc8a11f4409bcfb3c167090e" + "99d90a8543961b2ccd47724a3c460ba85183f4c5a7afe28302000000d05ff720b16c73761a3fcb67" + "5219061ab4c5c79489b2cc6a883c146972decb8b5adac8f5e6d66df46ea139107754dee62c36d2fc" + "e36f90d401000000fd41fe47684b370b6ec6584d64496089570968ead4d1ae91c819bb068196d599" + "efde3246e43f5e7945aaf95e2ffa3a11b9ef1b214d4647f5000000000f88e3759a08e7a56663861e" + "ea1bf42ccd3c72f2ad063857ca82ac5180101be4f85cef468ea086ea9aaafdc388811ec787bc45db" + "0422ae3f03000000c43bd794c697895e5bfe47c6f53a54e01b0c1d89fecd94d0e02d2ec587fc3300" + "03781b0f294a2b73c4421398f4de67e9cee64b38bc51e540030000006c3d048a92d3adc69a84eb47" + "622400207799416afef0a086fbd7e2f7dea0077ae9c0c0d9c386e9c6e6a2cbfa10ee58bdc7518360" + "36674cde0200000054cfe8f42bf0e9381ba2c4396de60f032bc7f34dfe959871c0d4c0d4eb720c4a" + "e3c9472e5f2da5d9c5cfd9f2343b21362c19a092b2cd3dbd01000000e958e48d2ab8b0313e7f8933" + "e315130fa9a84c82feb83f6e70b1646d8026e9f1704f1b16286ba2dabc7ef0820c91ed33ef60a8b5" + "bcfe97e1000000007ad742d3d7320a4f880cf47f5dd0cf69cb22840ffeb3fe7749509cb6752b2cee" + "30b7e7736a0afc9879ea40e69710fc9f6e8e99cd69121aec010000000fcc00ac2daa755e5292cd32" + "dc096cd5d8a4c5cffe91ee1cfcc2056cc1ff8e51bbce426cfa4b861cc78592be7b14e7ba9c15acb8" + "b83579b80300000072437f9b6245de39ec9e71ee4b951507beb42b34000000000000000000000000" + "00000001d639272e4a46eadfbd2146bf8cfdb205b3980deb020000006c1de913df1424ce3ee1d76f" + "c1ea76e98c9dfc7800000000000000000000000000000001e44ea74b4f2b83f9b3bee14d861a4c9e" + "cf844ef501000000cd743f59bd14c89b5cfd5ce6e82e7854152f2b70000000000000000000000000" + "0000000127e19f254ac9588319558041fc62ed561dce2f83020000003a3efc240b9977e166bee737" + "fe73670c439a644c000000000000000000000000000000015e0dfe491d1ba96742c7b5e02b227122" + "2af145480300000004265f6c72923e22594f3f79e208ed2e2ebb0771000000000000000000000000" + "0000000039dd8f88152a58454d9ca9d20f45dfa774993ade03000000e62112898dab2dade2ab2fc9" + "c56a7c86be5f962200000000000000000000000000000000bdd06352cb2c354434819f4b248eb2b8" + "922b6cb8030000001d5c302df59dd32a677e5a3af4fe297f608df061000000000000000000000000" + "000000008ae21e371051852c972ea7954079884a9f3c2c8803000000f51f44e644d7cf1d06b2b115" + "d882549e62c12fba000000000000000000000000000000004fc812bd2f8a59d96d064126666befbb" + "dc335c8b030000000a3c8e7c91bf821c4b09cee3c37ff4283a631480000000000000000000000000" + "000000005588456e4ead7cbda620a3abae816e34e3ff1a5f03000000b4425486c619147eb0216050" + "ed7afd741024e83600000000000000000000000000000000f493472201e48d163106cc397446a33f" + "f257b044030000006a4c619f9037d7a754655354c47cf0f551e96770000000000000000000000000" + "0000000050b8d10ab700cc3a7cf51be0403b654bbc74179403000000438a72e12ae0436a2495a609" + "675344f7e2e3a5eb0000000000000000000000000000000061eda239d9d083c3bf085387046ef8a3" + "4153e174020000004d89c0bb5408c1b7d17fb084d9e1825fa638e1af000000000000000000000000" + "000000006e08cb887464b9344ec3127c750fabdd6c0fc09c02000000809829af4a9df58dbfef186d" + "416f3a1ef170d10f0000000000000000000000000000000087780281d47a32f2235376239daeaacb" + "74e7860402000000cd7db68b9ae586dacdb4070c50320427c4dd3d03000000000000000000000000" + "00000000d538d34574c038404923e75d0e09e2fca9a89f8701000000fcdf6d9be94030b34774d1d7" + "dddedd9899f0f62700000000000000000000000000000000848518c4e3f6cbf25e5e1b990fc46767" + "fd338f35010000006e8cc34573654ea6624f138ef9531cd9367a02e4000000000000000000000000" + "00000000da40d88d40a6d75bc404156225b7eede2cb749e2010000000eb4f73e75039fcf251b32fc" + "79685b05ddd3aa9b000000000000000000000000000000000d58fbcc58fc4c2fd0d44ff1e51c3515" + "6aae660b01000000fc1fb23d24438387def0f4c6544e4b275d9b7146000000000000000000000000" + "00000000b883efebc09dd9d61966b7ae7412041db7f0318a01000000061db3dd7fde25654a4059d5" + "65dbc8a91e3b445700000000000000000000000000000000c1b5aad487c192f08bd7a09bdd214443" + "61c2f5d200000000b809d259e499db7dc8f1853bdcb0e4bc0e2b00b6000000000000000000000000" + "000000005e7fa0f02f2f3313d8469d09a92409c0b4d54acb00000000a417f3da01d99dae5f190096" + "cc582cabd5ddd15a00000000000000000000000000000000fdb3d117d76b0de5416f95e7bb75d72f" + "59747cf200000000ab2dadc5a39411fd4ff1116d478987316a553fc2000000000000000000000000" + "000000000819e3b10db116431ec6f7691539ce41b95c593100000000dbe9962069e66142e2275334" + "4fda8a3e0b841cf7000000000000000000000000000000008c54dda9ac3bb1b1d43e6505621b9a7f" + "fc2b445700000000496ad01bf007eacb0a28aec868282510b60291ea000000000000000000000000" + "000000005b29a197b7b3cceaf5f1bb12c535256a0436242c03000000ee3fbc164632d4f28aa28c08" + "f80dd50c6712dfb400000000000000000000000000000000078a806d329c9b008bbfc9723107f3f5" + "9a1b163a030000000e2f4f911a0dd8c052ed6b13e2815a1a37a52bdd000000000000000000000000" + "00000000bd99fcf72909ac9e7a55299e9bb4fd53fc1519de010000002545666937c22a3b6e9686dc" + "c405cbee5016c252000000000000000000000000000000006e4c699341b95f41d9c1e67743efb54e" + "d7ac5f9901000000822a272bec4501a1e27acfee7a8588ffd5a06cae000000000000000000000000" + "0000000077a47579dda0b6ead1e1b34901eaedd54f1b134803000000449a774929e86716ec852d59" + "f3d17232edd86ad6000000000000000000000000000000027dba1ee7e143fd52599364e13468f80f" + "40b26f6603000000badfad0fe8fa8f3c1aad2a82530b7447d9c2f401000000000000000000000000" + "000000028147507e1cd59ea1ae6da48b1eba6d16dedea2030100000002a1f8e6f5657f3f9e3eb807" + "cbad76451055edb800000000000000000000000000000002d9279fb2b8fcbac6abea74f7a6df7979" + "672d2fa501000000e276c5661a64192db44ce7af5eb888e9eb37bb04000000000000000000000000" + "00000002641e447514ca565fb9b68c08a5e4351e9f3c39f201000000de745cb25851429b3bbfb501" + "68dfd04edf6b35420000000000000000000000000000000218f93e742d08f0550b55726f2292362e" + "70ccc56700000000a4c73cf5ffa4ffc8a4bab14874afdf54e6aae816000000000000000000000000" + "0000000268baf76ab08940f6fc3bbdc7f6090f75f6989d2d000000006ff7add5df2c93e05459507b" + "5d8c6a0f466554d200000000000000000000ffff1785d3ffdbd9a617857ae8126b028c0e3e295354" + ), + }; + const int TEST_DATA_I = GPOINTER_TO_INT (test_data); + const int addr_family = (TEST_DATA_I == 0 ? AF_INET : AF_INET6); + const int IPV6_PREFER_TEMP = (TEST_DATA_I == 2); + const guint N_ADDRESSES = 100; + const gsize ELM_SIZE = addr_family == AF_INET + ? sizeof (NMPlatformIP4Address) + : sizeof (NMPlatformIP6Address); + const gboolean DO_REGENERATE = FALSE; + const gboolean PRINT_RESULT = DO_REGENERATE; + const gboolean CHECK_RESULT = !DO_REGENERATE; + gs_free guint8 *addresses = NULL; + gs_free guint64 *rand_map = NULL; + gsize i, j; + + /* + * First we create a list of addresses filled with (stable) random bytes. + * We tweak some fields explicitly (stable randomly), so that we cover all + * relevant cases. + * + * Then we sort the list of addresses, and compare that the result is + * as our EXPECTED_BUFFER. + */ + + addresses = g_malloc (ELM_SIZE * N_ADDRESSES); + rand_map = g_malloc (sizeof (rand_map[0]) * N_ADDRESSES); + nmtst_stable_rand (258829693, addresses, ELM_SIZE * N_ADDRESSES); + nmtst_stable_rand (710086081, rand_map, sizeof (rand_map[0]) * N_ADDRESSES); + + for (i = 0; i < N_ADDRESSES; i++) { + NMPlatformIPXAddress *a = (gpointer) (&addresses[i * ELM_SIZE]); + guint64 r = rand_map[i]; + struct in6_addr *a6; + +#define CONSUME_BITS(r, nbits) \ + ({ \ + guint64 _r = (r); \ + const int _nbits = (nbits); \ + \ + r >>= (_nbits); \ + (_r & (((((guint64) 1u) << (_nbits)) - 1u))); \ + }) + + if (addr_family == AF_INET) { + if (CONSUME_BITS (r, 1)) { + /* randomly create a link-local address or not. */ + g_assert ((NM_IPV4LL_NETWORK & ~NM_IPV4LL_NETMASK) == 0); + a->a4.address = (a->a4.address & ~NM_IPV4LL_NETMASK) + | NM_IPV4LL_NETWORK; + } + } else { + a6 = &a->a6.address; + switch (CONSUME_BITS (r, 4)) { + case 0: + a6->s6_addr32[0] = 0; + a6->s6_addr32[1] = 0; + a6->s6_addr32[2] = htonl (0xffff); + g_assert (IN6_IS_ADDR_V4MAPPED (a6)); + break; + case 1: + a6->s6_addr32[0] = 0; + a6->s6_addr32[1] = 0; + a6->s6_addr32[2] = 0; + a6->s6_addr32[3] = htonl (2); + g_assert (IN6_IS_ADDR_V4COMPAT (a6)); + break; + case 2: + a6->s6_addr32[0] = 0; + a6->s6_addr32[1] = 0; + a6->s6_addr32[2] = 0; + a6->s6_addr32[3] = 0; + g_assert (IN6_IS_ADDR_UNSPECIFIED (a6)); + break; + case 3: + a6->s6_addr32[0] = 0; + a6->s6_addr32[1] = 0; + a6->s6_addr32[2] = 0; + a6->s6_addr32[3] = htonl (1); + g_assert (IN6_IS_ADDR_LOOPBACK (a6)); + break; + case 4: + a6->s6_addr32[0] = (a6->s6_addr32[0] & ~htonl (0xffc00000)) + | htonl (0xfe800000); + g_assert (IN6_IS_ADDR_LINKLOCAL (a6)); + break; + case 6: + a6->s6_addr32[0] = (a6->s6_addr32[0] & ~htonl (0xffc00000)) + | htonl (0xfec00000); + g_assert (IN6_IS_ADDR_SITELOCAL (a6)); + break; + case 7: + case 8: + case 9: + case 10: + break; + default: + memset (a6, 0, sizeof (*a6)); + break; + } + } + + if (CONSUME_BITS (r, 5) != 0) { + /* randomly make addr-source the same (so that several addresses compare + * equal). */ + a->a4.addr_source = CONSUME_BITS (r, 2); + } + + if (addr_family == AF_INET) { + if (CONSUME_BITS (r, 1)) { + /* randomly make the label empty or not. */ + a->a4.label[0] = '\0'; + } + } + if (addr_family == AF_INET) { + if (CONSUME_BITS (r, 2) != 0) { + /* randomly make the label empty or not. */ + a->a4.plen = CONSUME_BITS (r, 2); + } + } + if (addr_family == AF_INET) { + if (CONSUME_BITS (r, 1)) { + a->a4.address = (a->a4.address & ~0xFFFFFFu) + | (CONSUME_BITS (r, 2) << 24); + } + } + } + + g_qsort_with_data (addresses, + N_ADDRESSES, + ELM_SIZE, + _address_pretty_sort_cmp, + (gpointer) test_data); + + for (i = 0; i < N_ADDRESSES; i++) { + const NMPlatformIPXAddress *a = (gconstpointer) (&addresses[i * ELM_SIZE]); + + for (j = i + 1; j < N_ADDRESSES; j++) { + const NMPlatformIPXAddress *b = (gconstpointer) (&addresses[j * ELM_SIZE]); + int c1; + int c2; + + if (addr_family == AF_INET) { + c1 = nm_platform_ip4_address_pretty_sort_cmp (&a->a4, &b->a4); + c2 = nm_platform_ip4_address_pretty_sort_cmp (&b->a4, &a->a4); + } else { + c1 = nm_platform_ip6_address_pretty_sort_cmp (&a->a6, &b->a6, IPV6_PREFER_TEMP); + c2 = nm_platform_ip6_address_pretty_sort_cmp (&b->a6, &a->a6, IPV6_PREFER_TEMP); + } + + g_assert_cmpint (c1, >=, -1); + g_assert_cmpint (c1, <=, 1); + g_assert_cmpint (c1, ==, -c2); + } + } + + if (PRINT_RESULT) { + g_print ("\n\n\t\t[%d] = (\n", TEST_DATA_I); + for (i = 0; i < ELM_SIZE * N_ADDRESSES; ) { + g_print ("\t\t\t\""); + for (j = 0; j < 40 && i < ELM_SIZE * N_ADDRESSES; j++, i++) + g_print ("%02x", addresses[i]); + g_print ("\"\n"); + } + g_print ("\t\t),\n\n"); + return; + } + + if (CHECK_RESULT) { + gs_free guint8 *bin_arr = NULL; + gsize bin_len; + + bin_arr = nm_utils_hexstr2bin_alloc (EXPECTED_BUFFER[TEST_DATA_I], FALSE, FALSE, NULL, 0, &bin_len); + g_assert_cmpmem (addresses, ELM_SIZE * N_ADDRESSES, bin_arr, bin_len); + } +} + +/*****************************************************************************/ + NMTST_DEFINE (); int @@ -72,6 +717,9 @@ main (int argc, char **argv) g_test_add_func ("/general/init_linux_platform", test_init_linux_platform); g_test_add_func ("/general/link_get_all", test_link_get_all); g_test_add_func ("/general/nm_platform_link_flags2str", test_nm_platform_link_flags2str); + g_test_add_data_func ("/general/platform_ip_address_pretty_sort_cmp/4", GINT_TO_POINTER (0), test_platform_ip_address_pretty_sort_cmp); + g_test_add_data_func ("/general/platform_ip_address_pretty_sort_cmp/6/1", GINT_TO_POINTER (1), test_platform_ip_address_pretty_sort_cmp); + g_test_add_data_func ("/general/platform_ip_address_pretty_sort_cmp/6/2", GINT_TO_POINTER (2), test_platform_ip_address_pretty_sort_cmp); return g_test_run (); }