[systemd-devel] [PATCH 3/6] libsystemd-dhcp: Add Init-Reboot support

Patrik Flykt patrik.flykt at linux.intel.com
Fri Jan 31 01:31:22 PST 2014


Init-Reboot is tried if a client IP address has been given when
the DHCP client is started. In Init-Reboot, start by sending a
broadcasted DHCP Request including the supplied client IP address
but without the server identifier. After sending the request,
enter Reboot state.

If a DHCP Ack is received, proceed to Bound state as usual. If a
DHCP Nak is received or the first timeout triggers, start the
address acquisition over from DHCP Init state.

See RFC 2131, sections 4.3.2, 4.4, 4.4.1 and 4.4.2 for details.
---
 src/libsystemd-dhcp/sd-dhcp-client.c | 59 ++++++++++++++++++++++++++++++++----
 1 file changed, 53 insertions(+), 6 deletions(-)

diff --git a/src/libsystemd-dhcp/sd-dhcp-client.c b/src/libsystemd-dhcp/sd-dhcp-client.c
index ffb304d..79a92e5 100644
--- a/src/libsystemd-dhcp/sd-dhcp-client.c
+++ b/src/libsystemd-dhcp/sd-dhcp-client.c
@@ -513,7 +513,17 @@ static int client_send_request(sd_dhcp_client *client, uint16_t secs) {
         if (err < 0)
                 return err;
 
-        if (client->state == DHCP_STATE_REQUESTING) {
+        switch (client->state) {
+
+        case DHCP_STATE_INIT_REBOOT:
+                err = dhcp_option_append(&opt, &optlen,
+                                         DHCP_OPTION_REQUESTED_IP_ADDRESS,
+                                         4, &client->last_addr);
+                if (err < 0)
+                        return err;
+                break;
+
+        case DHCP_STATE_REQUESTING:
                 err = dhcp_option_append(&opt, &optlen,
                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
                                          4, &client->lease->address);
@@ -525,6 +535,16 @@ static int client_send_request(sd_dhcp_client *client, uint16_t secs) {
                                          4, &client->lease->server_address);
                 if (err < 0)
                         return err;
+                break;
+
+        case DHCP_STATE_INIT:
+        case DHCP_STATE_SELECTING:
+        case DHCP_STATE_REBOOTING:
+        case DHCP_STATE_BOUND:
+        case DHCP_STATE_RENEWING:
+        case DHCP_STATE_REBINDING:
+
+                break;
         }
 
         err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
@@ -578,9 +598,14 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
                 next_timeout = usec + time_left * USEC_PER_SEC;
                 break;
 
+        case DHCP_STATE_REBOOTING:
+                /* start over as we did not receive a timely ack or nak */
+                client->state = DHCP_STATE_INIT;
+                client->attempt = 1;
+
+                /* fall through */
         case DHCP_STATE_INIT:
         case DHCP_STATE_INIT_REBOOT:
-        case DHCP_STATE_REBOOTING:
         case DHCP_STATE_SELECTING:
         case DHCP_STATE_REQUESTING:
         case DHCP_STATE_BOUND:
@@ -628,6 +653,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
 
                 break;
 
+        case DHCP_STATE_INIT_REBOOT:
         case DHCP_STATE_REQUESTING:
         case DHCP_STATE_RENEWING:
         case DHCP_STATE_REBINDING:
@@ -635,11 +661,13 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
                 if (r < 0 && client->attempt >= 64)
                          goto error;
 
+                if (client->state == DHCP_STATE_INIT_REBOOT)
+                        client->state = DHCP_STATE_REBOOTING;
+
                 client->request_sent = usec;
 
                 break;
 
-        case DHCP_STATE_INIT_REBOOT:
         case DHCP_STATE_REBOOTING:
         case DHCP_STATE_BOUND:
 
@@ -1096,20 +1124,37 @@ static int client_receive_message(sd_event_source *s, int fd,
 
                 break;
 
+        case DHCP_STATE_REBOOTING:
         case DHCP_STATE_REQUESTING:
         case DHCP_STATE_RENEWING:
         case DHCP_STATE_REBINDING:
 
                 r = client_receive_ack(client, buf, len);
 
-                if (r == DHCP_EVENT_NO_LEASE)
+                if (r == DHCP_EVENT_NO_LEASE) {
+
+                        client->timeout_resend =
+                                sd_event_source_unref(client->timeout_resend);
+
+                        if (client->state == DHCP_STATE_REBOOTING) {
+                                client->state = DHCP_STATE_INIT;
+                                client->attempt = 1;
+                                client->receive_message =
+                                        sd_event_source_unref(client->receive_message);
+
+                                client_initialize_events(client, time_now);
+                                return 0;
+                        }
+
                         goto error;
+                }
 
                 if (r >= 0) {
                         client->timeout_resend =
                                 sd_event_source_unref(client->timeout_resend);
 
-                        if (client->state == DHCP_STATE_REQUESTING)
+                        if (client->state == DHCP_STATE_REQUESTING ||
+                                client->state == DHCP_STATE_REBOOTING)
                                 notify_event = DHCP_EVENT_IP_ACQUIRE;
                         else if (r != DHCP_EVENT_IP_ACQUIRE)
                                 notify_event = r;
@@ -1138,7 +1183,6 @@ static int client_receive_message(sd_event_source *s, int fd,
 
         case DHCP_STATE_INIT:
         case DHCP_STATE_INIT_REBOOT:
-        case DHCP_STATE_REBOOTING:
         case DHCP_STATE_BOUND:
 
                 break;
@@ -1160,6 +1204,9 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
         assert_return(client->state == DHCP_STATE_INIT ||
                       client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
 
+        if (client->last_addr)
+                client->state = DHCP_STATE_INIT_REBOOT;
+
         client->xid = random_u32();
 
         r = dhcp_network_bind_raw_socket(client->index, &client->link);
-- 
1.8.5.2



More information about the systemd-devel mailing list