usec_t t1_time;
usec_t t2_time;
usec_t expire_time;
- uint64_t attempt;
- uint64_t max_attempts;
+ uint64_t discover_attempt;
+ uint64_t request_attempt;
+ uint64_t max_discover_attempts;
+ uint64_t max_request_attempts;
OrderedHashmap *extra_options;
OrderedHashmap *vendor_options;
sd_event_source *timeout_t1;
uint32_t revents,
void *userdata);
static void client_stop(sd_dhcp_client *client, int error);
+static int client_restart(sd_dhcp_client *client);
int dhcp_client_set_state_callback(
sd_dhcp_client *client,
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
- client->max_attempts = max_attempts;
+ client->max_discover_attempts = max_attempts;
return 0;
}
(void) event_source_disable(client->timeout_expire);
(void) event_source_disable(client->timeout_ipv6_only_mode);
- client->attempt = 0;
+ client->discover_attempt = 0;
+ client->request_attempt = 0;
client_set_state(client, DHCP_STATE_STOPPED);
client->xid = 0;
case DHCP_STATE_INIT:
case DHCP_STATE_INIT_REBOOT:
case DHCP_STATE_SELECTING:
+ if (client->discover_attempt >= client->max_discover_attempts)
+ goto error;
+
+ client->discover_attempt++;
+ next_timeout = client_compute_request_timeout(time_now, client->discover_attempt);
+ break;
case DHCP_STATE_REQUESTING:
case DHCP_STATE_BOUND:
- if (client->attempt >= client->max_attempts)
+ if (client->request_attempt >= client->max_request_attempts)
goto error;
- client->attempt++;
- next_timeout = client_compute_request_timeout(time_now, client->attempt);
+ client->request_attempt++;
+ next_timeout = client_compute_request_timeout(time_now, client->request_attempt);
break;
case DHCP_STATE_STOPPED:
r = client_send_discover(client);
if (r >= 0) {
client_set_state(client, DHCP_STATE_SELECTING);
- client->attempt = 0;
- } else if (client->attempt >= client->max_attempts)
+ client->discover_attempt = 0;
+ } else if (client->discover_attempt >= client->max_discover_attempts)
goto error;
break;
case DHCP_STATE_SELECTING:
r = client_send_discover(client);
- if (r < 0 && client->attempt >= client->max_attempts)
+ if (r < 0 && client->discover_attempt >= client->max_discover_attempts)
goto error;
break;
case DHCP_STATE_RENEWING:
case DHCP_STATE_REBINDING:
r = client_send_request(client);
- if (r < 0 && client->attempt >= client->max_attempts)
+ if (r < 0 && client->request_attempt >= client->max_request_attempts)
goto error;
if (client->state == DHCP_STATE_INIT_REBOOT)
goto error;
}
- if (client->attempt >= TRANSIENT_FAILURE_ATTEMPTS)
+ if (client->discover_attempt >= TRANSIENT_FAILURE_ATTEMPTS)
client_notify(client, SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE);
return 0;
error:
+ /* Avoid REQUEST infinite loop. Per RFC 2131 section 3.1.5: if the client receives
+ neither a DHCPACK or a DHCPNAK message after employing the retransmission algorithm,
+ the client reverts to INIT state and restarts the initialization process */
+ if (client->request_attempt >= client->max_request_attempts) {
+ log_dhcp_client(client, "Max REQUEST attempts reached. Restarting...");
+ client_restart(client);
+ return 0;
+ }
client_stop(client, r);
/* Errors were dealt with when stopping the client, don't spill
client->fd = safe_close(client->fd);
client_set_state(client, DHCP_STATE_REBINDING);
- client->attempt = 0;
+ client->discover_attempt = 0;
+ client->request_attempt = 0;
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
&client->hw_addr, &client->bcast_addr,
client_set_state(client, DHCP_STATE_RENEWING);
else if (client->state != DHCP_STATE_INIT)
client_set_state(client, DHCP_STATE_INIT_REBOOT);
- client->attempt = 0;
+ client->discover_attempt = 0;
+ client->request_attempt = 0;
return client_initialize_time_events(client);
}
assert(client);
client_set_state(client, DHCP_STATE_REQUESTING);
- client->attempt = 0;
+ client->discover_attempt = 0;
+ client->request_attempt = 0;
return event_reset_time(client->event, &client->timeout_resend,
CLOCK_BOOTTIME, 0, 0,
notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
client_set_state(client, DHCP_STATE_BOUND);
- client->attempt = 0;
+ client->discover_attempt = 0;
+ client->request_attempt = 0;
client->last_addr = client->lease->address;
assert(client->lease);
client->start_delay = 0;
- client->attempt = 1;
+ client->discover_attempt = 1;
+ client->request_attempt = 1;
client_set_state(client, DHCP_STATE_RENEWING);
return client_initialize_time_events(client);
.mtu = DHCP_MIN_PACKET_SIZE,
.port = DHCP_PORT_CLIENT,
.anonymize = !!anonymize,
- .max_attempts = UINT64_MAX,
+ .max_discover_attempts = UINT64_MAX,
+ .max_request_attempts = 5,
.ip_service_type = -1,
};
/* NOTE: this could be moved to a function. */