-/* $OpenBSD: dhclient.c,v 1.712 2021/03/16 20:21:54 krw Exp $ */
+/* $OpenBSD: dhclient.c,v 1.713 2021/03/24 16:04:10 krw Exp $ */
/*
* Copyright 2004 Henning Brauer <henning@openbsd.org>
void state_bound(struct interface_info *);
void state_panic(struct interface_info *);
-void set_interval(struct interface_info *, time_t);
-void set_secs(struct interface_info *, time_t);
+void set_interval(struct interface_info *, struct timespec *);
+void set_resend_timeout(struct interface_info *, struct timespec *,
+ void (*where)(struct interface_info *));
+void set_secs(struct interface_info *, struct timespec *);
void send_discover(struct interface_info *);
void send_request(struct interface_info *);
state_reboot(struct interface_info *ifi)
{
const struct timespec reboot_intvl = {config->reboot_interval, 0};
- struct timespec now;
struct client_lease *lease;
cancel_timeout(ifi);
make_request(ifi, ifi->active);
ifi->destination.s_addr = INADDR_BROADCAST;
- clock_gettime(CLOCK_REALTIME, &now);
- ifi->first_sending = now.tv_sec;
- timespecadd(&now, &reboot_intvl, &ifi->reboot_timeout);
+ clock_gettime(CLOCK_REALTIME, &ifi->first_sending);
+ timespecadd(&ifi->first_sending, &reboot_intvl, &ifi->reboot_timeout);
ifi->interval = 0;
send_request(ifi);
state_init(struct interface_info *ifi)
{
const struct timespec offer_intvl = {config->offer_interval, 0};
- struct timespec now;
ifi->xid = arc4random();
make_discover(ifi, ifi->active);
ifi->destination.s_addr = INADDR_BROADCAST;
ifi->state = S_SELECTING;
- clock_gettime(CLOCK_REALTIME, &now);
- ifi->first_sending = now.tv_sec;
- timespecadd(&now, &offer_intvl, &ifi->offer_timeout);
+ clock_gettime(CLOCK_REALTIME, &ifi->first_sending);
+ timespecadd(&ifi->first_sending, &offer_intvl, &ifi->offer_timeout);
ifi->select_timeout = ifi->offer_timeout;
ifi->interval = 0;
}
ifi->destination.s_addr = INADDR_BROADCAST;
- time(&ifi->first_sending);
+ clock_gettime(CLOCK_REALTIME, &ifi->first_sending);
ifi->interval = 0;
/*
const char *src)
{
const struct timespec select_intvl = {config->select_interval, 0};
- struct timespec now, remaining;
+ struct timespec now;
struct client_lease *lease;
clock_gettime(CLOCK_REALTIME, &now);
if (timespeccmp(&now, &ifi->select_timeout, >=))
state_selecting(ifi);
else {
- timespecsub(&ifi->select_timeout, &now, &remaining);
- if (remaining.tv_sec == 0 || remaining.tv_nsec > 500000000LL)
- remaining.tv_sec++;
- log_debug("%s: waiting %lld seconds for better offers",
- log_procname, (long long)remaining.tv_sec);
- set_timeout(ifi, remaining.tv_sec, state_selecting);
+ ifi->timeout = ifi->select_timeout;
+ ifi->timeout_func = state_selecting;
}
}
else
dest->s_addr = INADDR_BROADCAST;
- time(&ifi->first_sending);
+ clock_gettime(CLOCK_REALTIME, &ifi->first_sending);
ifi->interval = 0;
ifi->state = S_RENEWING;
}
void
-set_interval(struct interface_info *ifi, time_t cur_time)
+set_interval(struct interface_info *ifi, struct timespec *now)
{
- time_t interval = ifi->interval;
+ struct timespec interval;
+
+ if (timespeccmp(now, &ifi->timeout, >))
+ ifi->interval = 1;
+ else {
+ timespecsub(&ifi->timeout, now, &interval);
+ if (interval.tv_sec == 0 || interval.tv_nsec > 500000000LL)
+ interval.tv_sec++;
+ ifi->interval = interval.tv_sec;
+ }
+}
- if (interval == 0) {
+void
+set_resend_timeout(struct interface_info *ifi, struct timespec *now,
+ void (*where)(struct interface_info *))
+{
+ const struct timespec expiry = {ifi->expiry, 0};
+ const struct timespec reboot_intvl = {config->reboot_interval, 0};
+ const struct timespec initial_intvl = {config->initial_interval, 0};
+ const struct timespec cutoff_intvl = {config->backoff_cutoff, 0};
+ const struct timespec onesecond = {1, 0};
+ struct timespec interval, when;
+
+ if (timespeccmp(now, &ifi->link_timeout, <))
+ interval = onesecond;
+ else if (ifi->interval == 0) {
if (ifi->state == S_REBOOTING)
- interval = config->reboot_interval;
+ interval = reboot_intvl;
else
- interval = config->initial_interval;
+ interval = initial_intvl;
} else {
- interval += arc4random_uniform(2 * interval);
- if (interval > config->backoff_cutoff)
- interval = config->backoff_cutoff;
+ timespecclear(&interval);
+ interval.tv_sec = ifi->interval + arc4random_uniform(2 *
+ ifi->interval);
}
+ if (timespeccmp(&interval, &onesecond, <))
+ interval = onesecond;
+ else if (timespeccmp(&interval, &cutoff_intvl, >))
+ interval = cutoff_intvl;
+ timespecadd(now, &interval, &when);
switch (ifi->state) {
case S_REBOOTING:
case S_RENEWING:
- if (cur_time + interval > ifi->expiry)
- interval = ifi->expiry - cur_time;
+ if (timespeccmp(&when, &expiry, >))
+ when = expiry;
break;
case S_SELECTING:
- if (cur_time + interval > ifi->select_timeout.tv_sec)
- interval = ifi->select_timeout.tv_sec - cur_time;
+ if (timespeccmp(&when, &ifi->select_timeout, >))
+ when = ifi->select_timeout;
break;
case S_REQUESTING:
- if (cur_time + interval > ifi->offer_timeout.tv_sec)
- interval = ifi->offer_timeout.tv_sec - cur_time;
+ if (timespeccmp(&when, &ifi->offer_timeout, >))
+ when = ifi->offer_timeout;
break;
default:
break;
}
- ifi->interval = interval ? interval : 1;
+ ifi->timeout = when;
+ ifi->timeout_func = where;
}
void
-set_secs(struct interface_info *ifi, time_t cur_time)
+set_secs(struct interface_info *ifi, struct timespec *now)
{
- time_t secs;
+ struct timespec interval;
if (ifi->state != S_REQUESTING) {
/* Update the number of seconds since we started sending. */
- secs = cur_time - ifi->first_sending;
- if (secs > UINT16_MAX)
- secs = UINT16_MAX;
- ifi->secs = secs;
+ timespecsub(now, &ifi->first_sending, &interval);
+ if (interval.tv_nsec > 500000000LL)
+ interval.tv_sec++;
+ if (interval.tv_sec > UINT16_MAX)
+ ifi->secs = UINT16_MAX;
+ else
+ ifi->secs = interval.tv_sec;
}
ifi->sent_packet.secs = htons(ifi->secs);
{
struct timespec now;
ssize_t rslt;
- time_t cur_time;
clock_gettime(CLOCK_REALTIME, &now);
- cur_time = now.tv_sec;
-
if (timespeccmp(&now, &ifi->offer_timeout, >=)) {
state_panic(ifi);
return;
}
- if (timespeccmp(&now, &ifi->link_timeout, <))
- ifi->interval = 1;
- else
- set_interval(ifi, cur_time);
- set_secs(ifi, cur_time);
+ set_resend_timeout(ifi, &now, send_discover);
+ set_interval(ifi, &now);
+ set_secs(ifi, &now);
rslt = send_packet(ifi, inaddr_any, inaddr_broadcast, "DHCPDISCOVER");
if (rslt != -1)
(long long)ifi->interval);
tick_msg("lease", TICK_WAIT);
- set_timeout(ifi, ifi->interval, send_discover);
}
/*
return;
}
- if (timespeccmp(&now, &ifi->link_timeout, <))
- ifi->interval = 1;
- else
- set_interval(ifi, cur_time);
- set_secs(ifi, cur_time);
+ set_resend_timeout(ifi, &now, send_request);
+ set_interval(ifi, &now);
+ set_secs(ifi, &now);
rslt = send_packet(ifi, from, destination.sin_addr, "DHCPREQUEST");
if (rslt != -1)
inet_ntoa(destination.sin_addr));
tick_msg("lease", TICK_WAIT);
- set_timeout(ifi, ifi->interval, send_request);
}
void