Imported Upstream version 1.29
[platform/upstream/connman.git] / src / dhcpv6.c
index 5f8029f..bdb3b98 100644 (file)
@@ -105,25 +105,37 @@ static void clear_timer(struct connman_dhcpv6 *dhcp)
        }
 }
 
-static inline float get_random(void)
+static inline guint get_random(void)
 {
-       return (rand() % 200 - 100) / 1000.0;
+       uint64_t val;
+
+       __connman_util_get_random(&val);
+
+       /* 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)
@@ -1095,7 +1107,7 @@ static void re_cb(enum request_type req_type, GDHCPClient *dhcp_client,
                        if (!option) {
                                switch (req_type) {
                                case REQ_REQUEST:
-                                       dhcpv6_request(dhcp, true);
+                                       do_resend_request(dhcp);
                                        break;
                                case REQ_REBIND:
                                        dhcpv6_rebind(dhcp);
@@ -1220,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);
 
@@ -1387,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);
 
@@ -1585,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);
 
@@ -1601,6 +1613,7 @@ int __connman_dhcpv6_start_info(struct connman_network *network,
 {
        struct connman_dhcpv6 *dhcp;
        int delay;
+       uint64_t rand;
 
        DBG("");
 
@@ -1626,7 +1639,8 @@ int __connman_dhcpv6_start_info(struct connman_network *network,
        g_hash_table_replace(network_table, network, dhcp);
 
        /* Initial timeout, RFC 3315, 18.1.5 */
-       delay = rand() % 1000;
+       __connman_util_get_random(&rand);
+       delay = rand % 1000;
 
        dhcp->timeout = g_timeout_add(delay, start_info_req, dhcp);
 
@@ -1650,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);
 
@@ -1668,9 +1682,16 @@ static void solicitation_cb(GDHCPClient *dhcp_client, gpointer user_data)
 
        clear_timer(dhcp);
 
-       do_dad(dhcp_client, dhcp);
-
        g_dhcpv6_client_clear_retransmit(dhcp_client);
+
+       if (g_dhcpv6_client_get_status(dhcp_client) != 0) {
+               if (dhcp->callback)
+                       dhcp->callback(dhcp->network,
+                                       CONNMAN_DHCPV6_STATUS_FAIL, NULL);
+               return;
+       }
+
+       do_dad(dhcp_client, dhcp);
 }
 
 static gboolean timeout_solicitation(gpointer user_data)
@@ -1761,7 +1782,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);
 
@@ -1778,6 +1799,7 @@ int __connman_dhcpv6_start(struct connman_network *network,
        struct connman_service *service;
        struct connman_dhcpv6 *dhcp;
        int delay;
+       uint64_t rand;
 
        DBG("");
 
@@ -1807,7 +1829,8 @@ int __connman_dhcpv6_start(struct connman_network *network,
        g_hash_table_replace(network_table, network, dhcp);
 
        /* Initial timeout, RFC 3315, 17.1.2 */
-       delay = rand() % 1000;
+       __connman_util_get_random(&rand);
+       delay = rand % 1000;
 
        /*
         * Start from scratch.
@@ -2171,7 +2194,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);
 
@@ -2223,7 +2246,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);
 
@@ -2260,7 +2283,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);
 
@@ -2476,7 +2499,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);
 
@@ -2531,7 +2554,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);
 
@@ -2640,8 +2663,6 @@ int __connman_dhcpv6_init(void)
 {
        DBG("");
 
-       srand(time(NULL));
-
        network_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
                                                        NULL, remove_network);