From 3dc34fcc97b41f8b7b019027225b121dfbb9871d Mon Sep 17 00:00:00 2001 From: Patrik Flykt Date: Wed, 25 Jun 2014 14:06:02 +0300 Subject: sd-dhcp6-client: Implement Renew and Rebind Start sending Renew and Rebind DHCPv6 messages when respective timers T1 and T2 expire. Rebind messages do not include a Server ID option and the Rebind procedure ends when the last IPv6 address valid lifetime expires, whereafter the client restarts the address acquisition procedure by Soliciting for available servers. See RFC 3315, sections 18.1.3. and 18.1.4. for details. --- src/libsystemd-network/dhcp6-protocol.h | 6 +++ src/libsystemd-network/sd-dhcp6-client.c | 68 +++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index 37a8671a00..e9ae598b7a 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -57,6 +57,10 @@ enum { #define DHCP6_REQ_TIMEOUT 1 * USEC_PER_SEC #define DHCP6_REQ_MAX_RT 120 * USEC_PER_SEC #define DHCP6_REQ_MAX_RC 10 +#define DHCP6_REN_TIMEOUT 10 * USEC_PER_SEC +#define DHCP6_REN_MAX_RT 600 * USEC_PER_SEC +#define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC +#define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC enum { DHCP6_DUID_LLT = 1, @@ -71,6 +75,8 @@ enum DHCP6State { DHCP6_STATE_SOLICITATION = 2, DHCP6_STATE_REQUEST = 3, DHCP6_STATE_BOUND = 4, + DHCP6_STATE_RENEW = 5, + DHCP6_STATE_REBIND = 6, }; enum { diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 5d65603dc2..60d502fcbe 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -259,7 +259,12 @@ static int client_send_message(sd_dhcp6_client *client) { break; case DHCP6_STATE_REQUEST: - message->type = DHCP6_REQUEST; + case DHCP6_STATE_RENEW: + + if (client->state == DHCP6_STATE_REQUEST) + message->type = DHCP6_REQUEST; + else + message->type = DHCP6_RENEW; r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_SERVERID, client->lease->serverid_len, @@ -273,6 +278,15 @@ static int client_send_message(sd_dhcp6_client *client) { break; + case DHCP6_STATE_REBIND: + message->type = DHCP6_REBIND; + + r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia); + if (r < 0) + return r; + + break; + case DHCP6_STATE_STOPPED: case DHCP6_STATE_RS: case DHCP6_STATE_BOUND: @@ -314,6 +328,8 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, log_dhcp6_client(client, "Timeout T2"); + client_start(client, DHCP6_STATE_REBIND); + return 0; } @@ -330,19 +346,30 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, log_dhcp6_client(client, "Timeout T1"); + client_start(client, DHCP6_STATE_RENEW); + return 0; } static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp6_client *client = userdata; + DHCP6_CLIENT_DONT_DESTROY(client); + enum DHCP6State state; assert(s); assert(client); assert(client->event); + state = client->state; + client_stop(client, DHCP6_EVENT_RESEND_EXPIRE); + /* RFC 3315, section 18.1.4., says that "...the client may choose to + use a Solicit message to locate a new DHCP server..." */ + if (state == DHCP6_STATE_REBIND) + client_start(client, DHCP6_STATE_SOLICITATION); + return 0; } @@ -359,6 +386,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, usec_t max_retransmit_duration; uint8_t max_retransmit_count = 0; char time_string[FORMAT_TIMESPAN_MAX]; + uint32_t expire = 0; assert(s); assert(client); @@ -389,6 +417,37 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, break; + case DHCP6_STATE_RENEW: + init_retransmit_time = DHCP6_REN_TIMEOUT; + max_retransmit_time = DHCP6_REN_MAX_RT; + max_retransmit_count = 0; + + /* RFC 3315, section 18.1.3. says max retransmit duration will + be the remaining time until T2. Instead of setting MRD, + wait for T2 to trigger with the same end result */ + max_retransmit_duration = 0; + + break; + + case DHCP6_STATE_REBIND: + init_retransmit_time = DHCP6_REB_TIMEOUT; + max_retransmit_time = DHCP6_REB_MAX_RT; + max_retransmit_count = 0; + + max_retransmit_duration = 0; + + if (!client->timeout_resend_expire) { + r = dhcp6_lease_ia_rebind_expire(&client->lease->ia, + &expire); + if (r < 0) { + client_stop(client, r); + return 0; + } + max_retransmit_duration = expire * USEC_PER_SEC; + } + + break; + case DHCP6_STATE_STOPPED: case DHCP6_STATE_RS: case DHCP6_STATE_BOUND: @@ -740,6 +799,9 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, break; case DHCP6_STATE_REQUEST: + case DHCP6_STATE_RENEW: + case DHCP6_STATE_REBIND: + r = client_receive_reply(client, message, len); if (r < 0) return 0; @@ -822,6 +884,8 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) break; case DHCP6_STATE_REQUEST: + case DHCP6_STATE_RENEW: + case DHCP6_STATE_REBIND: client->state = state; @@ -883,6 +947,8 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) if (r < 0) return r; + client->state = state; + return 0; } -- cgit v1.2.3-54-g00ecf