chiark / gitweb /
libsystemd-dhcp: Update secs field only when sending Discover
[elogind.git] / src / libsystemd-dhcp / sd-dhcp-client.c
index 3b7b9f4ccdcad712eef8ba25cef6dc0751d234ea..3b3785809e957fb950c84f2ae1f6884057cb666b 100644 (file)
@@ -75,6 +75,7 @@ struct sd_dhcp_client {
         struct ether_addr mac_addr;
         uint32_t xid;
         usec_t start_time;
+        uint16_t secs;
         unsigned int attempt;
         usec_t request_sent;
         sd_event_source *timeout_t1;
@@ -240,21 +241,6 @@ int sd_dhcp_client_get_hostname(sd_dhcp_client *client, const char **hostname) {
         return 0;
 }
 
-int sd_dhcp_client_prefixlen(const struct in_addr *addr) {
-        int len = 0;
-        uint32_t mask;
-
-        assert_return(addr, -EADDRNOTAVAIL);
-
-        mask = be32toh(addr->s_addr);
-        while (mask) {
-                len++;
-                mask = mask << 1;
-        }
-
-        return len;
-}
-
 int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr) {
         assert_return(client, -EINVAL);
         assert_return(addr, -EINVAL);
@@ -317,24 +303,9 @@ static int client_stop(sd_dhcp_client *client, int error) {
 
         client_notify(client, error);
 
-        switch (client->state) {
-
-        case DHCP_STATE_INIT:
-        case DHCP_STATE_SELECTING:
-        case DHCP_STATE_REQUESTING:
-        case DHCP_STATE_BOUND:
-
-                client->start_time = 0;
-                client->state = DHCP_STATE_INIT;
-                break;
-
-        case DHCP_STATE_INIT_REBOOT:
-        case DHCP_STATE_REBOOTING:
-        case DHCP_STATE_RENEWING:
-        case DHCP_STATE_REBINDING:
-
-                break;
-        }
+        client->start_time = 0;
+        client->secs = 0;
+        client->state = DHCP_STATE_INIT;
 
         if (client->lease) {
                 lease_free(client->lease);
@@ -546,12 +517,18 @@ static int client_send_request(sd_dhcp_client *client, uint16_t secs) {
         return err;
 }
 
+static uint16_t client_update_secs(sd_dhcp_client *client, usec_t time_now)
+{
+        client->secs = (time_now - client->start_time) / USEC_PER_SEC;
+
+        return client->secs;
+}
+
 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
                                  void *userdata) {
         sd_dhcp_client *client = userdata;
         usec_t next_timeout = 0;
         uint32_t time_left;
-        uint16_t secs;
         int r = 0;
 
         assert(s);
@@ -606,11 +583,12 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
         if (r < 0)
                 goto error;
 
-        secs = (usec - client->start_time) / USEC_PER_SEC;
-
         switch (client->state) {
         case DHCP_STATE_INIT:
-                r = client_send_discover(client, secs);
+
+                client_update_secs(client, usec);
+
+                r = client_send_discover(client, client->secs);
                 if (r >= 0) {
                         client->state = DHCP_STATE_SELECTING;
                         client->attempt = 1;
@@ -622,7 +600,9 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
                 break;
 
         case DHCP_STATE_SELECTING:
-                r = client_send_discover(client, secs);
+                client_update_secs(client, usec);
+
+                r = client_send_discover(client, client->secs);
                 if (r < 0 && client->attempt >= 64)
                         goto error;
 
@@ -631,7 +611,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
         case DHCP_STATE_REQUESTING:
         case DHCP_STATE_RENEWING:
         case DHCP_STATE_REBINDING:
-                r = client_send_request(client, secs);
+                r = client_send_request(client, client->secs);
                 if (r < 0 && client->attempt >= 64)
                          goto error;
 
@@ -741,7 +721,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
         return client_initialize_events(client, usec);
 }
 
-static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
+static int client_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
                               void *user_data) {
         DHCPLease *lease = user_data;
         be32_t val;
@@ -775,7 +755,7 @@ static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
                 break;
 
         case DHCP_OPTION_DOMAIN_NAME_SERVER:
-                if (len >= 4) {
+                if (len && !(len % 4)) {
                         unsigned i;
 
                         lease->dns_size = len / 4;
@@ -853,13 +833,18 @@ static int client_verify_headers(sd_dhcp_client *client, DHCPPacket *message,
                                                            hdrlen))
                 return -EINVAL;
 
-        message->ip.check = message->udp.len;
-        message->ip.ttl = 0;
-
-        if (hdrlen + be16toh(message->udp.len) > len ||
-            client_checksum(&message->ip.ttl, be16toh(message->udp.len) + 12))
+        if (hdrlen + be16toh(message->udp.len) > len)
                 return -EINVAL;
 
+        if (message->udp.check) {
+                message->ip.check = message->udp.len;
+                message->ip.ttl = 0;
+
+                if (client_checksum(&message->ip.ttl,
+                                    be16toh(message->udp.len) + 12))
+                        return -EINVAL;
+        }
+
         if (be16toh(message->udp.source) != DHCP_PORT_SERVER ||
             be16toh(message->udp.dest) != DHCP_PORT_CLIENT)
                 return -EINVAL;
@@ -891,7 +876,7 @@ static int client_receive_offer(sd_dhcp_client *client, DHCPPacket *offer,
                 return -ENOMEM;
 
         len = len - DHCP_IP_UDP_SIZE;
-        r = dhcp_option_parse(&offer->dhcp, len, client_parse_offer,
+        r = dhcp_option_parse(&offer->dhcp, len, client_parse_options,
                               lease);
         if (r != DHCP_OFFER)
                 return -ENOMSG;
@@ -934,7 +919,7 @@ static int client_receive_ack(sd_dhcp_client *client, const uint8_t *buf,
         if (!lease)
                 return -ENOMEM;
 
-        r = dhcp_option_parse(dhcp, len, client_parse_offer, lease);
+        r = dhcp_option_parse(dhcp, len, client_parse_options, lease);
         if (r == DHCP_NAK)
                 return DHCP_EVENT_NO_LEASE;
 
@@ -1171,6 +1156,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
 
         client->fd = r;
         client->start_time = now(CLOCK_MONOTONIC);
+        client->secs = 0;
 
         return client_initialize_events(client, client->start_time);
 }