bool request_broadcast;
Set *req_opts;
bool anonymize;
+ bool rapid_commit;
be32_t last_addr;
struct hw_addr_data hw_addr;
struct hw_addr_data bcast_addr;
return 0;
}
+int sd_dhcp_client_set_rapid_commit(sd_dhcp_client *client, bool rapid_commit) {
+ assert_return(client, -EINVAL);
+
+ client->rapid_commit = !client->anonymize && rapid_commit;
+ return 0;
+}
+
int sd_dhcp_client_set_hostname(
sd_dhcp_client *client,
const char *hostname) {
return r;
}
+ if (client->rapid_commit) {
+ r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+ SD_DHCP_OPTION_RAPID_COMMIT, 0, NULL);
+ if (r < 0)
+ return r;
+ }
+
r = client_append_common_discover_request_options(client, discover, &optoffset, optlen);
if (r < 0)
return r;
if (r < 0 && client->attempt >= client->max_attempts)
goto error;
+ if (client->rapid_commit)
+ client->request_sent = time_now;
+
break;
case DHCP_STATE_INIT_REBOOT:
switch (client->state) {
case DHCP_STATE_SELECTING:
- if (r != DHCP_OFFER)
+ if (r == DHCP_ACK) {
+ if (!client->rapid_commit)
+ return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
+ "received unexpected ACK, ignoring.");
+ if (!lease->rapid_commit)
+ return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
+ "received rapid ACK without Rapid Commit option, ignoring.");
+ } else if (r == DHCP_OFFER) {
+ if (lease->rapid_commit)
+ return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
+ "received OFFER with Rapid Commit option, ignoring");
+ if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0)
+ lease->lifetime = client->fallback_lease_lifetime;
+ } else
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
- "received message was not an OFFER, ignoring.");
-
- if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0)
- lease->lifetime = client->fallback_lease_lifetime;
+ "received unexpected message, ignoring.");
break;
return 0;
}
-static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *message, size_t len) {
+static int client_handle_offer_or_rapid_ack(sd_dhcp_client *client, DHCPMessage *message, size_t len) {
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
int r;
dhcp_lease_unref_and_replace(client->lease, lease);
+ if (client->lease->rapid_commit) {
+ log_dhcp_client(client, "ACK");
+ return SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
+ }
+
if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0)
return -ENOMSG;
return client_enter_bound_now(client, notify_event);
}
+static int client_restart(sd_dhcp_client *client) {
+ int r;
+ assert(client);
+
+ client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
+
+ r = client_initialize(client);
+ if (r < 0)
+ return r;
+
+ r = client_start_delayed(client);
+ if (r < 0)
+ return r;
+
+ log_dhcp_client(client, "REBOOT in %s", FORMAT_TIMESPAN(client->start_delay, USEC_PER_SEC));
+
+ client->start_delay = CLAMP(client->start_delay * 2,
+ RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
+ return 0;
+}
+
static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) {
DHCP_CLIENT_DONT_DESTROY(client);
int r;
switch (client->state) {
case DHCP_STATE_SELECTING:
- r = client_handle_offer(client, message, len);
+ r = client_handle_offer_or_rapid_ack(client, message, len);
if (ERRNO_IS_NEG_RESOURCE(r))
goto error;
+
+ if (r == -EADDRNOTAVAIL) {
+ /* got a rapid NAK, let's restart the client */
+ r = client_restart(client);
+ if (r < 0)
+ goto error;
+
+ return 0;
+ }
if (r < 0)
return 0; /* invalid message, let's ignore it */
- r = client_enter_requesting(client);
+ if (client->lease->rapid_commit)
+ /* got a succssful rapid commit */
+ r = client_enter_bound(client, r);
+ else
+ r = client_enter_requesting(client);
break;
case DHCP_STATE_REBOOTING:
goto error;
if (r == -EADDRNOTAVAIL) {
/* got a NAK, let's restart the client */
- client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
-
- r = client_initialize(client);
+ r = client_restart(client);
if (r < 0)
goto error;
- r = client_start_delayed(client);
- if (r < 0)
- goto error;
-
- log_dhcp_client(client, "REBOOT in %s", FORMAT_TIMESPAN(client->start_delay, USEC_PER_SEC));
-
- client->start_delay = CLAMP(client->start_delay * 2,
- RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
return 0;
}
if (r < 0)