}
}
-static inline float get_random(void)
+static guint compute_random(guint val)
{
- return (rand() % 200 - 100) / 1000.0;
+ uint64_t rand;
+
+ __connman_util_get_random(&rand);
+
+ return val - val / 10 +
+ ((guint) rand % (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 (rt > MRT)
- rt = MRT * (1 + delay);
+ if (MRT && (RT > MRT / 2))
+ RT = compute_random(MRT);
+ else
+ RT += compute_random(RT);
- 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)
int duid_len;
ident = __connman_service_get_ident(service);
+#if defined TIZEN_EXT
+ if(ident != NULL)
+ DBG("ident : %s", ident);
+#endif
keyfile = connman_storage_load_service(ident);
+
+#if defined TIZEN_EXT
+ if (!keyfile) {
+ keyfile = g_key_file_new();
+ if (!keyfile)
+ return -EIO;
+ }
+#else
if (!keyfile)
return -EINVAL;
+#endif
hex_duid = g_key_file_get_string(keyfile, ident, "IPv6.DHCP.DUID",
NULL);
hex_duid = convert_to_hex(duid, duid_len);
if (!hex_duid) {
+ g_free(duid);
g_key_file_free(keyfile);
return -ENOMEM;
}
if (!compare_string_arrays(nameservers, dhcp->nameservers)) {
if (dhcp->nameservers) {
for (i = 0; dhcp->nameservers[i]; i++)
+#if defined TIZEN_EXT
+ {
__connman_service_nameserver_remove(service,
- dhcp->nameservers[i],
- false);
+ dhcp->nameservers[i], false,
+ CONNMAN_IPCONFIG_TYPE_IPV6);
+#else
+ __connman_service_nameserver_remove(service,
+ dhcp->nameservers[i],
+ false);
+#endif
+#if defined TIZEN_EXT
+ }
+#endif
g_strfreev(dhcp->nameservers);
}
for (i = 0; dhcp->nameservers &&
dhcp->nameservers[i]; i++)
+#if defined TIZEN_EXT
+ {
+ __connman_service_nameserver_append(service,
+ dhcp->nameservers[i], false,
+ CONNMAN_IPCONFIG_TYPE_IPV6);
+#else
__connman_service_nameserver_append(service,
dhcp->nameservers[i],
false);
+#endif
+#if defined TIZEN_EXT
+ }
+#endif
} else
g_strfreev(nameservers);
return -EINVAL;
}
+#if !defined TIZEN_EXT
if (getenv("CONNMAN_DHCPV6_DEBUG"))
+#endif
g_dhcp_client_set_debug(dhcp_client, dhcpv6_debug, "DHCPv6");
service = connman_service_lookup_from_network(dhcp->network);
if (!slash)
continue;
- prefix = g_strndup(prefix, slash - prefix);
len = strtol(slash + 1, NULL, 10);
if (len < 3 || len > 128)
break;
left = plen % 8;
i = 16 - count;
+ prefix = g_strndup(prefix, slash - prefix);
inet_pton(AF_INET6, prefix, &addr_prefix);
inet_pton(AF_INET6, address, &addr);
for (i = 0, list = option; list;
list = list->next, i++)
domains[i] = g_strdup(list->data);
- __connman_service_update_search_domains(service, domains);
+ __connman_service_set_search_domains(service, domains);
g_strfreev(domains);
}
}
if (!compare_string_arrays(nameservers, dhcp->nameservers)) {
if (dhcp->nameservers) {
for (i = 0; dhcp->nameservers[i]; i++)
+#if defined TIZEN_EXT
+ {
+ __connman_service_nameserver_remove(service,
+ dhcp->nameservers[i],
+ false, CONNMAN_IPCONFIG_TYPE_IPV6);
+#else
__connman_service_nameserver_remove(service,
dhcp->nameservers[i],
false);
+#endif
+#if defined TIZEN_EXT
+ }
+#endif
g_strfreev(dhcp->nameservers);
}
for (i = 0; dhcp->nameservers &&
dhcp->nameservers[i]; i++)
+#if defined TIZEN_EXT
+ {
__connman_service_nameserver_append(service,
- dhcp->nameservers[i],
- false);
+ dhcp->nameservers[i],
+ false, CONNMAN_IPCONFIG_TYPE_IPV6);
+#else
+ __connman_service_nameserver_append(service,
+ dhcp->nameservers[i],
+ false);
+#endif
+#if defined TIZEN_EXT
+ }
+#endif
} else
g_strfreev(nameservers);
/* Is this prefix part of the subnet we are suppose to use? */
prefix_len = check_ipv6_addr_prefix(prefixes, address);
+#if defined TIZEN_EXT
+ char *gateway = g_strdup(__connman_ipconfig_get_gateway(ipconfig));
+#endif
+ __connman_ipconfig_address_remove(ipconfig);
__connman_ipconfig_set_local(ipconfig, address);
__connman_ipconfig_set_prefixlen(ipconfig, prefix_len);
DBG("new address %s/%d", address, prefix_len);
__connman_ipconfig_set_dhcp_address(ipconfig, address);
+#if defined TIZEN_EXT
+ DBG("Set gateway %s", gateway);
+ __connman_ipconfig_set_gateway(ipconfig, gateway);
+ g_free(gateway);
+#endif
__connman_service_save(
__connman_service_lookup_from_index(ifindex));
}
service = __connman_service_lookup_from_index(
data->ifindex);
network = __connman_service_get_network(service);
- data->callback(network, status, NULL);
+ if (network)
+ data->callback(network, status, NULL);
}
}
if (!option) {
switch (req_type) {
case REQ_REQUEST:
- dhcpv6_request(dhcp, true);
+ do_resend_request(dhcp);
break;
case REQ_REBIND:
dhcpv6_rebind(dhcp);
{
DBG("");
+ g_dhcpv6_client_reset_request(dhcp_client);
g_dhcpv6_client_clear_retransmit(dhcp_client);
re_cb(REQ_REBIND, dhcp_client, user_data);
g_dhcpv6_client_get_timeouts(dhcp->dhcp_client, NULL, NULL,
NULL, &expired);
+
+ /* infinite lifetime for an DHCPv6 address */
+ if (expired == 0xffffffff)
+ return -EISCONN;
+
current = time(NULL);
if (current >= expired) {
DBG("expired by %d secs", (int)(current - expired));
- g_timeout_add(0, dhcpv6_restart, dhcp);
+ g_idle_add(dhcpv6_restart, dhcp);
return -ETIMEDOUT;
}
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);
{
DBG("");
+ g_dhcpv6_client_reset_request(dhcp_client);
g_dhcpv6_client_clear_retransmit(dhcp_client);
re_cb(REQ_RENEW, dhcp_client, 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);
dhcpv6_cb callback)
{
struct connman_dhcpv6 *dhcp;
- uint32_t T1, T2;
+ uint32_t T1, T2, delta;
time_t started, current, expired;
dhcp = g_hash_table_lookup(network_table, network);
/* RFC 3315, 22.4 */
return 0;
- if (T1 == 0)
+ if (T1 == 0) {
/* RFC 3315, 22.4
* Client can choose the timeout.
*/
- T1 = 1800;
+ T1 = (expired - started) / 2;
+ T2 = (expired - started) / 10 * 8;
+ }
dhcp->callback = callback;
if (T2 != 0xffffffff && T2 > 0) {
if ((unsigned)current >= (unsigned)started + T2) {
/* RFC 3315, chapter 18.1.3, start rebind */
- DBG("rebind after %d secs", T2);
+ DBG("start rebind immediately");
- dhcp->timeout = g_timeout_add_seconds(T2, start_rebind,
- dhcp);
+ dhcp->timeout = g_idle_add(start_rebind, dhcp);
} else if ((unsigned)current < (unsigned)started + T1) {
- DBG("renew after %d secs", T1);
+ delta = started + T1 - current;
+ DBG("renew after %d secs", delta);
- dhcp->timeout = g_timeout_add_seconds(T1, start_renew,
- dhcp);
+ dhcp->timeout = g_timeout_add_seconds(delta,
+ start_renew, dhcp);
} else {
- DBG("rebind after %d secs", T2 - T1);
+ delta = started + T2 - current;
+ DBG("rebind after %d secs", delta);
- dhcp->timeout = g_timeout_add_seconds(T2 - T1,
- start_rebind,
- dhcp);
+ dhcp->timeout = g_timeout_add_seconds(delta,
+ start_rebind, dhcp);
}
}
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)
static int dhcpv6_solicitation(struct connman_dhcpv6 *dhcp)
{
struct connman_service *service;
+#if !defined TIZEN_EXT
struct connman_ipconfig *ipconfig_ipv6;
+#endif
GDHCPClient *dhcp_client;
GDHCPClientError error;
int index, ret;
return -EINVAL;
}
+#if !defined TIZEN_EXT
if (getenv("CONNMAN_DHCPV6_DEBUG"))
+#endif
g_dhcp_client_set_debug(dhcp_client, dhcpv6_debug, "DHCPv6");
service = connman_service_lookup_from_network(dhcp->network);
g_dhcpv6_client_set_oro(dhcp_client, 3, G_DHCPV6_DNS_SERVERS,
G_DHCPV6_DOMAIN_LIST, G_DHCPV6_SNTP_SERVERS);
+#if defined TIZEN_EXT
+ /**
+ When privacy extension is enabled then connman requests
+ OPTION_IA_TA (4) from DHCPv6 server. This option is used to request
+ temporary IPv6 address from DHCPv6 server but we found that DHCPv6
+ server never provided temporary IPv6 address and connman resend dhcpv6
+ requests. So always set OPTION_IA_NA in dhcpv6 request to get IPv6
+ address from DHCPv6 server.
+ */
+ dhcp->use_ta = FALSE;
+#else
ipconfig_ipv6 = __connman_service_get_ip6config(service);
dhcp->use_ta = __connman_ipconfig_ipv6_privacy_enabled(ipconfig_ipv6);
+#endif
g_dhcpv6_client_set_ia(dhcp_client, index,
dhcp->use_ta ? G_DHCPV6_IA_TA : G_DHCPV6_IA_NA,
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);
return FALSE;
}
-static void confirm_cb(GDHCPClient *dhcp_client, gpointer user_data)
-{
- struct connman_dhcpv6 *dhcp = user_data;
- int status = g_dhcpv6_client_get_status(dhcp_client);
-
- DBG("dhcpv6 confirm msg %p status %d", dhcp, status);
-
- clear_timer(dhcp);
-
- g_dhcpv6_client_clear_retransmit(dhcp_client);
-
- /*
- * If confirm fails, start from scratch.
- */
- if (status != 0) {
- g_dhcp_client_unref(dhcp->dhcp_client);
- start_solicitation(dhcp);
- } else {
- do_dad(dhcp_client, dhcp);
- }
-}
-
-static int dhcpv6_confirm(struct connman_dhcpv6 *dhcp)
-{
- GDHCPClient *dhcp_client;
- GDHCPClientError error;
- struct connman_service *service;
- struct connman_ipconfig *ipconfig_ipv6;
- int index, ret;
-
- DBG("dhcp %p", dhcp);
-
- index = connman_network_get_index(dhcp->network);
-
- dhcp_client = g_dhcp_client_new(G_DHCP_IPV6, index, &error);
- if (error != G_DHCP_CLIENT_ERROR_NONE) {
- clear_timer(dhcp);
- return -EINVAL;
- }
-
- if (getenv("CONNMAN_DHCPV6_DEBUG"))
- g_dhcp_client_set_debug(dhcp_client, dhcpv6_debug, "DHCPv6");
-
- service = connman_service_lookup_from_network(dhcp->network);
- if (!service) {
- clear_timer(dhcp);
- g_dhcp_client_unref(dhcp_client);
- return -EINVAL;
- }
-
- ret = set_duid(service, dhcp->network, dhcp_client, index);
- if (ret < 0) {
- clear_timer(dhcp);
- g_dhcp_client_unref(dhcp_client);
- return ret;
- }
-
- g_dhcp_client_set_request(dhcp_client, G_DHCPV6_CLIENTID);
- g_dhcp_client_set_request(dhcp_client, G_DHCPV6_RAPID_COMMIT);
-
- ipconfig_ipv6 = __connman_service_get_ip6config(service);
- dhcp->use_ta = __connman_ipconfig_ipv6_privacy_enabled(ipconfig_ipv6);
-
- g_dhcpv6_client_set_ia(dhcp_client, index,
- dhcp->use_ta ? G_DHCPV6_IA_TA : G_DHCPV6_IA_NA,
- NULL, NULL, TRUE,
- __connman_ipconfig_get_dhcp_address(ipconfig_ipv6));
-
- clear_callbacks(dhcp_client);
-
- g_dhcp_client_register_event(dhcp_client,
- G_DHCP_CLIENT_EVENT_CONFIRM,
- confirm_cb, dhcp);
-
- dhcp->dhcp_client = dhcp_client;
-
- return g_dhcp_client_start(dhcp_client, NULL);
-}
-
-static gboolean timeout_confirm(gpointer user_data)
-{
- struct connman_dhcpv6 *dhcp = user_data;
-
- dhcp->RT = calc_delay(dhcp->RT, CNF_MAX_RT);
-
- DBG("confirm RT timeout %d msec", dhcp->RT);
-
- dhcp->timeout = g_timeout_add(dhcp->RT, timeout_confirm, dhcp);
-
- g_dhcpv6_client_set_retransmit(dhcp->dhcp_client);
-
- g_dhcp_client_start(dhcp->dhcp_client, NULL);
-
- return FALSE;
-}
-
-static gboolean timeout_max_confirm(gpointer user_data)
-{
- struct connman_dhcpv6 *dhcp = user_data;
-
- dhcp->MRD = 0;
-
- clear_timer(dhcp);
-
- DBG("confirm max retransmit duration timeout");
-
- g_dhcpv6_client_clear_retransmit(dhcp->dhcp_client);
-
- if (dhcp->callback)
- dhcp->callback(dhcp->network, CONNMAN_DHCPV6_STATUS_FAIL,
- NULL);
-
- return FALSE;
-}
-
-static gboolean start_confirm(gpointer user_data)
-{
- struct connman_dhcpv6 *dhcp = user_data;
-
- /* Set the confirm timeout, RFC 3315 chapter 14 */
- dhcp->RT = CNF_TIMEOUT * (1 + get_random());
-
- DBG("confirm initial RT timeout %d msec", dhcp->RT);
-
- dhcp->timeout = g_timeout_add(dhcp->RT, timeout_confirm, dhcp);
- dhcp->MRD = g_timeout_add(CNF_MAX_RD, timeout_max_confirm, dhcp);
-
- dhcpv6_confirm(dhcp);
-
- return FALSE;
-}
-
int __connman_dhcpv6_start(struct connman_network *network,
GSList *prefixes, dhcpv6_cb callback)
{
struct connman_service *service;
- struct connman_ipconfig *ipconfig_ipv6;
struct connman_dhcpv6 *dhcp;
- char *last_address;
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;
- ipconfig_ipv6 = __connman_service_get_ip6config(service);
- last_address = __connman_ipconfig_get_dhcp_address(ipconfig_ipv6);
-
- if (prefixes && last_address &&
- check_ipv6_addr_prefix(prefixes,
- last_address) != 128) {
- /*
- * So we are in the same subnet
- * RFC 3315, chapter 18.1.2 Confirm message
- */
- dhcp->timeout = g_timeout_add(delay, start_confirm, dhcp);
- } else {
- /*
- * Start from scratch.
- * RFC 3315, chapter 17.1.2 Solicitation message
- */
- dhcp->timeout = g_timeout_add(delay, start_solicitation, dhcp);
- }
+ /*
+ * Start from scratch.
+ * RFC 3315, chapter 17.1.2 Solicitation message
+ *
+ * Note that we do not send CONFIRM message here as it does
+ * not make much sense because we do not save expiration time
+ * so we cannot really know how long the saved address is valid
+ * anyway. The reply to CONFIRM message does not send
+ * expiration times back to us. Because of this we need to
+ * start using SOLICITATION anyway.
+ */
+ dhcp->timeout = g_timeout_add(delay, start_solicitation, dhcp);
return 0;
}
return NULL;
}
+#if !defined TIZEN_EXT
if (getenv("CONNMAN_DHCPV6_DEBUG"))
+#endif
g_dhcp_client_set_debug(dhcp_client, dhcpv6_debug, "DHCPv6:PD");
service = connman_service_lookup_from_network(dhcp->network);
if (current > expired) {
DBG("expired by %d secs", (int)(current - expired));
- g_timeout_add(0, dhcpv6_restart, dhcp);
+ g_idle_add(dhcpv6_restart, dhcp);
return -ETIMEDOUT;
}
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);