}
}
-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)
if (!option) {
switch (req_type) {
case REQ_REQUEST:
- dhcpv6_request(dhcp, true);
+ do_resend_request(dhcp);
break;
case REQ_REBIND:
dhcpv6_rebind(dhcp);
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);
{
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);
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);
{
struct connman_dhcpv6 *dhcp;
int delay;
+ uint64_t rand;
DBG("");
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);
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);
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)
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);
struct connman_service *service;
struct connman_dhcpv6 *dhcp;
int delay;
+ uint64_t rand;
DBG("");
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.
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);
{
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);
{
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);
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);
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);
{
DBG("");
- srand(time(NULL));
-
network_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, remove_network);