From 7246333cb803b03440d3bd0bdaa233564d09b5ae Mon Sep 17 00:00:00 2001 From: Patrik Flykt Date: Thu, 19 Jun 2014 15:39:53 +0300 Subject: [PATCH] sd-dhcp6-client: Add Request message sending As described in RFC 3315, Section 17.1.2, a client has to wait until the first timeout has elapsed before it is allowed to request IPv6 addresses from the DHCPv6 server. This is indicated by a non-NULL lease and a non-zero resend count. Should the Advertisement contain a preference value of 255 or be received after the first timeout, IPv6 address requesting is started immediately. In response to these events, create a Request message and set up proper resend timers to send the message to the server. --- src/libsystemd-network/dhcp6-protocol.h | 4 ++ src/libsystemd-network/sd-dhcp6-client.c | 47 ++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index 1303a55a8..754e80008 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -54,6 +54,9 @@ enum { #define DHCP6_SOL_MAX_DELAY 1 * USEC_PER_SEC #define DHCP6_SOL_TIMEOUT 1 * USEC_PER_SEC #define DHCP6_SOL_MAX_RT 120 * USEC_PER_SEC +#define DHCP6_REQ_TIMEOUT 1 * USEC_PER_SEC +#define DHCP6_REQ_MAX_RT 120 * USEC_PER_SEC +#define DHCP6_REQ_MAX_RC 10 enum { DHCP6_DUID_LLT = 1, @@ -66,6 +69,7 @@ enum DHCP6State { DHCP6_STATE_STOPPED = 0, DHCP6_STATE_RS = 1, DHCP6_STATE_SOLICITATION = 2, + DHCP6_STATE_REQUEST = 3, }; enum { diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 1a59cc286..55dd65c9e 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -213,12 +213,22 @@ static int client_send_message(sd_dhcp6_client *client) { case DHCP6_STATE_SOLICITATION: message->type = DHCP6_SOLICIT; - r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID, - sizeof(client->duid), &client->duid); + r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na); if (r < 0) return r; - r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na); + break; + + case DHCP6_STATE_REQUEST: + message->type = DHCP6_REQUEST; + + r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_SERVERID, + client->lease->serverid_len, + client->lease->serverid); + if (r < 0) + return r; + + r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia); if (r < 0) return r; @@ -229,6 +239,11 @@ static int client_send_message(sd_dhcp6_client *client) { return -EINVAL; } + r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID, + sizeof(client->duid), &client->duid); + if (r < 0) + return r; + r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message, len - optlen); if (r < 0) @@ -275,6 +290,12 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, switch (client->state) { case DHCP6_STATE_SOLICITATION: + + if (client->retransmit_count && client->lease) { + client_start(client, DHCP6_STATE_REQUEST); + return 0; + } + init_retransmit_time = DHCP6_SOL_TIMEOUT; max_retransmit_time = DHCP6_SOL_MAX_RT; max_retransmit_count = 0; @@ -282,6 +303,14 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, break; + case DHCP6_STATE_REQUEST: + init_retransmit_time = DHCP6_REQ_TIMEOUT; + max_retransmit_time = DHCP6_REQ_MAX_RT; + max_retransmit_count = DHCP6_REQ_MAX_RC; + max_retransmit_duration = 0; + + break; + case DHCP6_STATE_STOPPED: case DHCP6_STATE_RS: return 0; @@ -537,6 +566,9 @@ static int client_receive_advertise(sd_dhcp6_client *client, r = 0; } + if (pref_advertise == 255 || client->retransmit_count > 1) + r = DHCP6_STATE_REQUEST; + return r; } @@ -596,8 +628,12 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, case DHCP6_STATE_SOLICITATION: r = client_receive_advertise(client, message, len); + if (r == DHCP6_STATE_REQUEST) + client_start(client, r); + break; + case DHCP6_STATE_REQUEST: case DHCP6_STATE_STOPPED: case DHCP6_STATE_RS: return 0; @@ -654,6 +690,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) client->state = DHCP6_STATE_SOLICITATION; + break; + + case DHCP6_STATE_REQUEST: + client->state = state; + break; } -- 2.30.2