From e1410b5a88cbfc33d79ba43cef317d6990a7e7d1 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 31 Mar 2014 11:19:45 +0200 Subject: [PATCH] platform: refactor calculating valid/preferred times when adding address Replace the calls to subtract_guint32() by _rebase_relative_time_on_now() and _address_get_lifetime(). Signed-off-by: Thomas Haller --- src/platform/nm-platform.c | 73 +++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 3993d59341..d8b6b76579 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1559,14 +1559,53 @@ array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address return FALSE; } -/* Compute (a - b) in an overflow-safe manner. */ +/** + * Takes a pair @timestamp and @duration, and returns the remaining duration based + * on the new timestamp @now. + */ static guint32 -subtract_guint32 (guint32 a, guint32 b) +_rebase_relative_time_on_now (guint32 timestamp, guint32 duration, guint32 now) { - if (a == G_MAXUINT32) - return G_MAXUINT32; + gint64 t; - return a > b ? a - b : 0; + if (duration == NM_PLATFORM_LIFETIME_PERMANENT) + return NM_PLATFORM_LIFETIME_PERMANENT; + + /* For timestamp>now, just accept it and calculate the expected(?) result. */ + t = (gint64) timestamp + (gint64) duration - (gint64) now; + + /* Pad the timestamp by 5 seconds to avoid potential races. */ + t += 5; + + if (t <= 0) + return 0; + if (t >= NM_PLATFORM_LIFETIME_PERMANENT) + return NM_PLATFORM_LIFETIME_PERMANENT - 1; + return t; +} + +static gboolean +_address_get_lifetime (const NMPlatformIPAddress *address, guint32 now, guint32 *out_lifetime, guint32 *out_preferred) +{ + gint32 lifetime, preferred; + + if (address->lifetime == 0) { + *out_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + *out_preferred = NM_PLATFORM_LIFETIME_PERMANENT; + } else { + lifetime = _rebase_relative_time_on_now (address->timestamp, address->lifetime, now); + if (!lifetime) + return FALSE; + preferred = _rebase_relative_time_on_now (address->timestamp, address->preferred, now); + if (preferred > lifetime) { + g_warn_if_reached (); + preferred = lifetime; + } + + *out_lifetime = lifetime; + *out_preferred = preferred; + } + return TRUE; } /** @@ -1606,16 +1645,8 @@ nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses) const NMPlatformIP4Address *known_address = &g_array_index (known_addresses, NMPlatformIP4Address, i); guint32 lifetime, preferred; - if (known_address->lifetime) { - /* Pad the timestamp by 5 seconds to avoid potential races. */ - guint32 shift = subtract_guint32 (now, known_address->timestamp + 5); - - lifetime = subtract_guint32 (known_address->lifetime, shift); - preferred = subtract_guint32 (known_address->preferred, shift); - - g_warn_if_fail (known_address->preferred <= known_address->lifetime); - } else - lifetime = preferred = NM_PLATFORM_LIFETIME_PERMANENT; + if (!_address_get_lifetime ((NMPlatformIPAddress *) known_address, now, &lifetime, &preferred)) + continue; if (!nm_platform_ip4_address_add (ifindex, known_address->address, known_address->peer_address, known_address->plen, lifetime, preferred, known_address->label)) return FALSE; @@ -1665,16 +1696,8 @@ nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses) const NMPlatformIP6Address *known_address = &g_array_index (known_addresses, NMPlatformIP6Address, i); guint32 lifetime, preferred; - if (known_address->lifetime) { - /* Pad the timestamp by 5 seconds to avoid potential races. */ - guint32 shift = subtract_guint32 (now, known_address->timestamp + 5); - - lifetime = subtract_guint32 (known_address->lifetime, shift); - preferred = subtract_guint32 (known_address->preferred, shift); - - g_warn_if_fail (known_address->preferred <= known_address->lifetime); - } else - lifetime = preferred = NM_PLATFORM_LIFETIME_PERMANENT; + if (!_address_get_lifetime ((NMPlatformIPAddress *) known_address, now, &lifetime, &preferred)) + continue; if (!nm_platform_ip6_address_add (ifindex, known_address->address, known_address->peer_address, known_address->plen,