about summary refs log tree commit diff
path: root/shared/n-dhcp4/src/n-dhcp4-c-probe.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared/n-dhcp4/src/n-dhcp4-c-probe.c')
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-probe.c101
1 files changed, 94 insertions, 7 deletions
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-probe.c b/shared/n-dhcp4/src/n-dhcp4-c-probe.c
index 2bced4cf..4fb7d389 100644
--- a/shared/n-dhcp4/src/n-dhcp4-c-probe.c
+++ b/shared/n-dhcp4/src/n-dhcp4-c-probe.c
@@ -170,8 +170,6 @@ _c_public_ void n_dhcp4_client_probe_config_set_inform_only(NDhcp4ClientProbeCon
  * INIT-REBOOT path, as described by the DHCP specification. In most cases, you
  * do not want this.
  *
- * XXX: This is currently not implemented, and setting the property has no effect.
- *
  * Background: The INIT-REBOOT path allows a DHCP client to skip
  *             server-discovery when rebooting/resuming their machine. The DHCP
  *             client simply re-requests the lease it had acquired before. This
@@ -438,11 +436,17 @@ int n_dhcp4_client_probe_new(NDhcp4ClientProbe **probep,
         if (r)
                 return r;
 
+        if (probe->config->init_reboot && probe->config->requested_ip.s_addr != INADDR_ANY)
+                probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT;
+        else
+                probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
+
         if (active) {
                 /*
                  * Defer the sending of DISCOVER by a random amount (by default up to 9 seconds).
                  */
-                probe->ns_deferred = ns_now + (n_dhcp4_client_probe_config_get_random(probe->config) % (probe->config->ms_start_delay * 1000000ULL));
+                if (probe->state == N_DHCP4_CLIENT_PROBE_STATE_INIT)
+                        probe->ns_deferred = ns_now + (n_dhcp4_client_probe_config_get_random(probe->config) % (probe->config->ms_start_delay * 1000000ULL));
                 probe->client->current_probe = probe;
         } else {
                 r = n_dhcp4_client_probe_raise(probe,
@@ -575,6 +579,14 @@ void n_dhcp4_client_probe_get_timeout(NDhcp4ClientProbe *probe, uint64_t *timeou
         n_dhcp4_c_connection_get_timeout(&probe->connection, &timeout);
 
         switch (probe->state) {
+        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
+                /* send DHCP request immediately */
+                timeout = 1;
+                break;
+        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
+                if (probe->ns_reinit && (!timeout || probe->ns_reinit < timeout))
+                        timeout = probe->ns_reinit;
+                break;
         case N_DHCP4_CLIENT_PROBE_STATE_INIT:
                 if (probe->ns_deferred && (!timeout || probe->ns_deferred < timeout))
                         timeout = probe->ns_deferred;
@@ -626,6 +638,52 @@ static int n_dhcp4_client_probe_outgoing_append_options(NDhcp4ClientProbe *probe
         return 0;
 }
 
+static int n_dhcp4_client_probe_transition_reboot(NDhcp4ClientProbe *probe, uint64_t ns_now) {
+        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
+        int r;
+
+        switch (probe->state) {
+        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
+                r = n_dhcp4_c_connection_listen(&probe->connection);
+                if (r)
+                        return r;
+
+                r = n_dhcp4_c_connection_reboot_new(&probe->connection, &request, &probe->config->requested_ip);
+                if (r)
+                        return r;
+
+                r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
+                if (r)
+                        return r;
+
+                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
+                if (r)
+                        return r;
+                else
+                        request = NULL; /* consumed */
+
+                probe->state = N_DHCP4_CLIENT_PROBE_STATE_REBOOTING;
+                probe->ns_reinit = ns_now + 2000000000ULL;
+
+                break;
+
+        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
+        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
+        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
+        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
+        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
+        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
+        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
+        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
+        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
+        default:
+                abort();
+                break;
+        }
+
+        return 0;
+}
+
 static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, uint64_t ns_now) {
         _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
         int r;
@@ -635,12 +693,14 @@ static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, ui
                 r = n_dhcp4_c_connection_listen(&probe->connection);
                 if (r)
                         return r;
+                /* fall-through */
 
+        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
                 r = n_dhcp4_c_connection_discover_new(&probe->connection, &request);
                 if (r)
                         return r;
 
-                if (probe->config->requested_ip.s_addr != INADDR_ANY) {
+                if (!probe->config->init_reboot && probe->config->requested_ip.s_addr != INADDR_ANY) {
                         r = n_dhcp4_outgoing_append_requested_ip(request, probe->config->requested_ip);
                         if (r)
                                 return r;
@@ -663,7 +723,6 @@ static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, ui
 
         case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
         case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
         case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
         case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
         case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
@@ -726,6 +785,10 @@ static int n_dhcp4_client_probe_transition_t2(NDhcp4ClientProbe *probe, uint64_t
         switch (probe->state) {
         case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
         case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
+                r = n_dhcp4_c_connection_listen(&probe->connection);
+                if (r)
+                        return r;
+
                 r = n_dhcp4_c_connection_rebind_new(&probe->connection, &request);
                 if (r)
                         return r;
@@ -848,11 +911,22 @@ static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4I
         _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = message_take;
         _c_cleanup_(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
         NDhcp4CEventNode *node;
+        struct in_addr client = {};
+        struct in_addr server = {};
         int r;
 
         switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
         case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
+                n_dhcp4_incoming_get_yiaddr(message, &client);
+
+                r = n_dhcp4_incoming_query_server_identifier(message, &server);
+                if (r)
+                        return r;
+                r = n_dhcp4_c_connection_connect(&probe->connection, &client, &server);
+                if (r)
+                        return r;
+                /* fall-through */
+        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
 
                 r = n_dhcp4_client_probe_raise(probe,
                                                &node,
@@ -876,6 +950,7 @@ static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4I
                 break;
 
         case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
+        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
 
                 r = n_dhcp4_client_probe_raise(probe,
                                                &node,
@@ -900,7 +975,6 @@ static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4I
         case N_DHCP4_CLIENT_PROBE_STATE_INIT:
         case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
         case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
         case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
         case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
         case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
@@ -1079,6 +1153,19 @@ int n_dhcp4_client_probe_dispatch_timer(NDhcp4ClientProbe *probe, uint64_t ns_no
         int r;
 
         switch (probe->state) {
+        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
+                r = n_dhcp4_client_probe_transition_reboot(probe, ns_now);
+                if (r)
+                        return r;
+                break;
+        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
+                if (ns_now >= probe->ns_reinit) {
+                        r = n_dhcp4_client_probe_transition_deferred(probe, ns_now);
+                        if (r)
+                                return r;
+                }
+
+                break;
         case N_DHCP4_CLIENT_PROBE_STATE_INIT:
                 if (ns_now >= probe->ns_deferred) {
                         r = n_dhcp4_client_probe_transition_deferred(probe, ns_now);