The conversion from uint64_t to float caused the RT value
to become 0. This caused the transmission timeout to expire
immediately and the machine load to go to 100%.

This is fixed by using directly uints instead of floats.
---
 src/dhcpv6.c | 49 +++++++++++++++++++++++++++++--------------------
 1 file changed, 29 insertions(+), 20 deletions(-)

diff --git a/src/dhcpv6.c b/src/dhcpv6.c
index c311045..9249e55 100644
--- a/src/dhcpv6.c
+++ b/src/dhcpv6.c
@@ -105,28 +105,37 @@ static void clear_timer(struct connman_dhcpv6 *dhcp)
        }
 }
 
-static inline float get_random(void)
+static inline guint get_random(void)
 {
        uint64_t val;
 
        __connman_util_get_random(&val);
-       return (val % 200 - 100) / 1000.0;
+
+       /* Make sure the value is always positive so strip MSB */
+       return ((uint32_t)val) >> 1;
+}
+
+static guint compute_random(guint val)
+{
+       return val - val / 10 +
+               (get_random() % (2 * 1000)) * val / 10 / 1000;
 }
 
 /* Calculate a random delay, RFC 3315 chapter 14 */
 /* RT and MRT are milliseconds */
 static guint calc_delay(guint RT, guint MRT)
 {
-       float delay = get_random();
-       float rt = RT * (2 + delay);
+       if (MRT && (RT > MRT / 2))
+               RT = compute_random(MRT);
+       else
+               RT += compute_random(RT);
 
-       if (rt > MRT)
-               rt = MRT * (1 + delay);
-
-       if (rt < 0)
-               rt = MRT;
+       return RT;
+}
 
-       return (guint)rt;
+static guint initial_rt(guint timeout)
+{
+       return compute_random(timeout);
 }
 
 static void free_prefix(gpointer data)
@@ -1223,7 +1232,7 @@ static gboolean start_rebind(gpointer user_data)
        if (check_restart(dhcp) < 0)
                return FALSE;
 
-       dhcp->RT = REB_TIMEOUT * (1 + get_random());
+       dhcp->RT = initial_rt(REB_TIMEOUT);
 
        DBG("rebind initial RT timeout %d msec", dhcp->RT);
 
@@ -1390,7 +1399,7 @@ static gboolean start_renew(gpointer user_data)
 {
        struct connman_dhcpv6 *dhcp = user_data;
 
-       dhcp->RT = REN_TIMEOUT * (1 + get_random());
+       dhcp->RT = initial_rt(REN_TIMEOUT);
 
        DBG("renew initial RT timeout %d msec", dhcp->RT);
 
@@ -1588,7 +1597,7 @@ static gboolean start_info_req(gpointer user_data)
        struct connman_dhcpv6 *dhcp = user_data;
 
        /* Set the retransmission timeout, RFC 3315 chapter 14 */
-       dhcp->RT = INF_TIMEOUT * (1 + get_random());
+       dhcp->RT = initial_rt(INF_TIMEOUT);
 
        DBG("info initial RT timeout %d msec", dhcp->RT);
 
@@ -1655,7 +1664,7 @@ static void advertise_cb(GDHCPClient *dhcp_client, 
gpointer user_data)
                return;
        }
 
-       dhcp->RT = REQ_TIMEOUT * (1 + get_random());
+       dhcp->RT = initial_rt(REQ_TIMEOUT);
        DBG("request initial RT timeout %d msec", dhcp->RT);
        dhcp->timeout = g_timeout_add(dhcp->RT, timeout_request, dhcp);
 
@@ -1766,7 +1775,7 @@ static gboolean start_solicitation(gpointer user_data)
        struct connman_dhcpv6 *dhcp = user_data;
 
        /* Set the retransmission timeout, RFC 3315 chapter 14 */
-       dhcp->RT = SOL_TIMEOUT * (1 + get_random());
+       dhcp->RT = initial_rt(SOL_TIMEOUT);
 
        DBG("solicit initial RT timeout %d msec", dhcp->RT);
 
@@ -2178,7 +2187,7 @@ static gboolean start_pd_rebind(gpointer user_data)
        if (check_pd_restart(dhcp) < 0)
                return FALSE;
 
-       dhcp->RT = REB_TIMEOUT * (1 + get_random());
+       dhcp->RT = initial_rt(REB_TIMEOUT);
 
        DBG("rebind initial RT timeout %d msec", dhcp->RT);
 
@@ -2230,7 +2239,7 @@ static gboolean start_pd_rebind_with_confirm(gpointer 
user_data)
 {
        struct connman_dhcpv6 *dhcp = user_data;
 
-       dhcp->RT = CNF_TIMEOUT * (1 + get_random());
+       dhcp->RT = initial_rt(CNF_TIMEOUT);
 
        DBG("rebind with confirm initial RT timeout %d msec", dhcp->RT);
 
@@ -2267,7 +2276,7 @@ static gboolean start_pd_renew(gpointer user_data)
 {
        struct connman_dhcpv6 *dhcp = user_data;
 
-       dhcp->RT = REN_TIMEOUT * (1 + get_random());
+       dhcp->RT = initial_rt(REN_TIMEOUT);
 
        DBG("renew initial RT timeout %d msec", dhcp->RT);
 
@@ -2483,7 +2492,7 @@ static void advertise_pd_cb(GDHCPClient *dhcp_client, 
gpointer user_data)
                return;
        }
 
-       dhcp->RT = REQ_TIMEOUT * (1 + get_random());
+       dhcp->RT = initial_rt(REQ_TIMEOUT);
        DBG("request initial RT timeout %d msec", dhcp->RT);
        dhcp->timeout = g_timeout_add(dhcp->RT, timeout_pd_request, dhcp);
 
@@ -2538,7 +2547,7 @@ static gboolean start_pd_solicitation(gpointer user_data)
        struct connman_dhcpv6 *dhcp = user_data;
 
        /* Set the retransmission timeout, RFC 3315 chapter 14 */
-       dhcp->RT = SOL_TIMEOUT * (1 + get_random());
+       dhcp->RT = initial_rt(SOL_TIMEOUT);
 
        DBG("solicit initial RT timeout %d msec", dhcp->RT);
 
-- 
1.8.3.1

_______________________________________________
connman mailing list
[email protected]
https://lists.connman.net/mailman/listinfo/connman

Reply via email to