sd-dhcp6-client: Add Request message sending
authorPatrik Flykt <patrik.flykt@linux.intel.com>
Thu, 19 Jun 2014 12:39:53 +0000 (15:39 +0300)
committerPatrik Flykt <patrik.flykt@linux.intel.com>
Thu, 19 Jun 2014 12:44:44 +0000 (15:44 +0300)
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
src/libsystemd-network/sd-dhcp6-client.c

index 1303a55..754e800 100644 (file)
@@ -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 {
index 1a59cc2..55dd65c 100644 (file)
@@ -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;
@@ -655,6 +691,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;
         }
 
         client->transaction_id = random_u32() & htobe32(0x00ffffff);