diff options
Diffstat (limited to 'src/dhcpv6.c')
-rw-r--r-- | src/dhcpv6.c | 197 |
1 files changed, 32 insertions, 165 deletions
diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 2ede854e..5f8029f1 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -631,6 +631,7 @@ static void set_address(int ifindex, struct connman_ipconfig *ipconfig, /* Is this prefix part of the subnet we are suppose to use? */ prefix_len = check_ipv6_addr_prefix(prefixes, address); + __connman_ipconfig_address_remove(ipconfig); __connman_ipconfig_set_local(ipconfig, address); __connman_ipconfig_set_prefixlen(ipconfig, prefix_len); @@ -804,7 +805,8 @@ static void dad_reply(struct nd_neighbor_advert *reply, 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); } } @@ -1118,6 +1120,7 @@ static void rebind_cb(GDHCPClient *dhcp_client, gpointer user_data) { DBG(""); + g_dhcpv6_client_reset_request(dhcp_client); g_dhcpv6_client_clear_retransmit(dhcp_client); re_cb(REQ_REBIND, dhcp_client, user_data); @@ -1305,6 +1308,7 @@ static void renew_cb(GDHCPClient *dhcp_client, gpointer user_data) { DBG(""); + g_dhcpv6_client_reset_request(dhcp_client); g_dhcpv6_client_clear_retransmit(dhcp_client); re_cb(REQ_RENEW, dhcp_client, user_data); @@ -1398,7 +1402,7 @@ int __connman_dhcpv6_start_renew(struct connman_network *network, 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); @@ -1421,11 +1425,13 @@ int __connman_dhcpv6_start_renew(struct connman_network *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; @@ -1436,22 +1442,23 @@ int __connman_dhcpv6_start_renew(struct connman_network *network, 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->timeout = g_timeout_add_seconds(0, 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); } } @@ -1765,145 +1772,11 @@ static gboolean start_solicitation(gpointer user_data) 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; DBG(""); @@ -1936,24 +1809,18 @@ int __connman_dhcpv6_start(struct connman_network *network, /* Initial timeout, RFC 3315, 17.1.2 */ 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; } |