chiark / gitweb /
sd-dhcp6-client: Implement Elapsed Time option
[elogind.git] / src / libsystemd-network / sd-dhcp6-client.c
index c6c82eb349161ec4d856b0648c968045e73a343d..c190b560eab01f698f65a1e35b5aea583be11fec 100644 (file)
@@ -49,6 +49,7 @@ struct sd_dhcp6_client {
         struct ether_addr mac_addr;
         DHCP6IA ia_na;
         be32_t transaction_id;
+        usec_t transaction_start;
         struct sd_dhcp6_lease *lease;
         int fd;
         be16_t *req_opts;
@@ -203,6 +204,7 @@ static int client_reset(sd_dhcp6_client *client) {
         client->fd = safe_close(client->fd);
 
         client->transaction_id = 0;
+        client->transaction_start = 0;
 
         client->ia_na.timeout_t1 =
                 sd_event_source_unref(client->ia_na.timeout_t1);
@@ -230,13 +232,15 @@ static void client_stop(sd_dhcp6_client *client, int error) {
         client_reset(client);
 }
 
-static int client_send_message(sd_dhcp6_client *client) {
+static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
         _cleanup_free_ DHCP6Message *message = NULL;
         struct in6_addr all_servers =
                 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
         size_t len, optlen = 512;
         uint8_t *opt;
         int r;
+        usec_t elapsed_usec;
+        be16_t elapsed_time;
 
         len = sizeof(DHCP6Message) + optlen;
 
@@ -308,6 +312,17 @@ static int client_send_message(sd_dhcp6_client *client) {
         if (r < 0)
                 return r;
 
+        elapsed_usec = time_now - client->transaction_start;
+        if (elapsed_usec < 0xffff * USEC_PER_MSEC * 10)
+                elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC / 10);
+        else
+                elapsed_time = 0xffff;
+
+        r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ELAPSED_TIME,
+                                sizeof(elapsed_time), &elapsed_time);
+        if (r < 0)
+                return r;
+
         r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
                                           len - optlen);
         if (r < 0)
@@ -455,15 +470,14 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
                 return 0;
         }
 
-        r = client_send_message(client);
-        if (r >= 0)
-                client->retransmit_count++;
-
-
         r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
         if (r < 0)
                 goto error;
 
+        r = client_send_message(client, time_now);
+        if (r >= 0)
+                client->retransmit_count++;
+
         if (!client->retransmit_time) {
                 client->retransmit_time =
                         client_timeout_compute_random(init_retransmit_time);
@@ -496,6 +510,11 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
         if (r < 0)
                 goto error;
 
+        r = sd_event_source_set_name(client->timeout_resend,
+                                     "dhcp6-resend-timer");
+        if (r < 0)
+                goto error;
+
         if (max_retransmit_duration && !client->timeout_resend_expire) {
 
                 log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
@@ -514,6 +533,11 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
                                                  client->event_priority);
                 if (r < 0)
                         goto error;
+
+                r = sd_event_source_set_name(client->timeout_resend_expire,
+                                             "dhcp6-resend-expire-timer");
+                if (r < 0)
+                        goto error;
         }
 
 error:
@@ -573,12 +597,15 @@ static int client_parse_message(sd_dhcp6_client *client,
                                 DHCP6Message *message, size_t len,
                                 sd_dhcp6_lease *lease) {
         int r;
-        uint8_t *optval, *option = (uint8_t *)(message + 1), *id = NULL;
+        uint8_t *optval, *option, *id = NULL;
         uint16_t optcode, status;
         size_t optlen, id_len;
         bool clientid = false;
         be32_t iaid_lease;
 
+        option = (uint8_t *)message + sizeof(DHCP6Message);
+        len -= sizeof(DHCP6Message);
+
         while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen,
                                        &optval)) >= 0) {
                 switch (optcode) {
@@ -707,7 +734,7 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply,
         }
 
         if (client->lease)
-            dhcp6_lease_clear_timers(&client->lease->ia);
+                dhcp6_lease_clear_timers(&client->lease->ia);
 
         client->lease = sd_dhcp6_lease_unref(client->lease);
         client->lease = lease;
@@ -869,6 +896,15 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
         client->retransmit_time = 0;
         client->retransmit_count = 0;
 
+        if (client->state == DHCP6_STATE_STOPPED) {
+                time_now = now(clock_boottime_or_monotonic());
+        } else {
+                r = sd_event_now(client->event, clock_boottime_or_monotonic(),
+                                 &time_now);
+                if (r < 0)
+                        return r;
+        }
+
         switch (state) {
         case DHCP6_STATE_STOPPED:
         case DHCP6_STATE_SOLICITATION:
@@ -894,6 +930,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
                 if (r < 0)
                         return r;
 
+                r = sd_event_source_set_name(client->receive_message,
+                                             "dhcp6-receive-message");
+                if (r < 0)
+                        return r;
+
                 client->state = DHCP6_STATE_SOLICITATION;
 
                 break;
@@ -908,10 +949,6 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
 
         case DHCP6_STATE_BOUND:
 
-                r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
-                if (r < 0)
-                        return r;
-
                 if (client->lease->ia.lifetime_t1 == 0xffffffff ||
                     client->lease->ia.lifetime_t2 == 0xffffffff) {
 
@@ -942,6 +979,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
                 if (r < 0)
                         return r;
 
+                r = sd_event_source_set_name(client->lease->ia.timeout_t1,
+                                             "dhcp6-t1-timeout");
+                if (r < 0)
+                        return r;
+
                 timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC);
 
                 log_dhcp6_client(client, "T2 expires in %s",
@@ -962,12 +1004,18 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
                 if (r < 0)
                         return r;
 
+                r = sd_event_source_set_name(client->lease->ia.timeout_t2,
+                                             "dhcp6-t2-timeout");
+                if (r < 0)
+                        return r;
+
                 client->state = state;
 
                 return 0;
         }
 
         client->transaction_id = random_u32() & htobe32(0x00ffffff);
+        client->transaction_start = time_now;
 
         r = sd_event_add_time(client->event, &client->timeout_resend,
                               clock_boottime_or_monotonic(), 0, 0, client_timeout_resend,
@@ -980,6 +1028,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
         if (r < 0)
                 return r;
 
+        r = sd_event_source_set_name(client->timeout_resend,
+                                     "dhcp6-resend-timeout");
+        if (r < 0)
+                return r;
+
         return 0;
 }