.sin6_family = AF_INET6,
.sin6_port = htons(DHCP6_SERVER_PORT),
};
- struct timespec RTprev;
- double rnd;
- time_t ms;
- uint8_t neg;
+ unsigned int RT;
const char *broad_uni;
const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
struct ipv6_addr *lla;
!(ifp->options->options & DHCPCD_INITIAL_DELAY))
state->IMD = 0;
if (state->IMD) {
+ state->RT = state->IMD * MSEC_PER_SEC;
/* Some buggy PPP servers close the link too early
* after sending an invalid status in their reply
* which means this host won't see it.
* 1 second grace seems to be the sweet spot. */
if (ifp->flags & IFF_POINTOPOINT)
- state->RT.tv_sec = 1;
- else
- state->RT.tv_sec = 0;
- state->RT.tv_nsec = (suseconds_t)arc4random_uniform(
- (uint32_t)(state->IMD * NSEC_PER_SEC));
- timespecnorm(&state->RT);
+ state->RT += MSEC_PER_SEC;
broad_uni = "delaying";
- goto logsend;
- }
- if (state->RTC == 0) {
- RTprev.tv_sec = state->IRT;
- RTprev.tv_nsec = 0;
- state->RT.tv_sec = RTprev.tv_sec;
- state->RT.tv_nsec = 0;
- } else {
- RTprev = state->RT;
- timespecadd(&state->RT, &state->RT, &state->RT);
- }
+ } else if (state->RTC == 0)
+ state->RT = state->IRT * MSEC_PER_SEC;
- rnd = DHCP6_RAND_MIN;
- rnd += (suseconds_t)arc4random_uniform(
- DHCP6_RAND_MAX - DHCP6_RAND_MIN);
- rnd /= MSEC_PER_SEC;
- neg = (rnd < 0.0);
- if (neg)
- rnd = -rnd;
- ts_to_ms(ms, &RTprev);
- ms = (time_t)((double)ms * rnd);
- ms_to_ts(&RTprev, ms);
- if (neg)
- timespecsub(&state->RT, &RTprev, &state->RT);
- else
- timespecadd(&state->RT, &RTprev, &state->RT);
-
- if (state->MRT != 0 && state->RT.tv_sec > state->MRT) {
- RTprev.tv_sec = state->MRT;
- RTprev.tv_nsec = 0;
- state->RT.tv_sec = state->MRT;
- state->RT.tv_nsec = 0;
- ts_to_ms(ms, &RTprev);
- ms = (time_t)((double)ms * rnd);
- ms_to_ts(&RTprev, ms);
- if (neg)
- timespecsub(&state->RT, &RTprev, &state->RT);
- else
- timespecadd(&state->RT, &RTprev, &state->RT);
+ if (state->MRT != 0) {
+ unsigned int mrt = state->MRT * MSEC_PER_SEC;
+
+ if (state->RT > mrt)
+ state->RT = mrt;
}
-logsend:
+ /* Add -.1 to .1 * RT randomness as per RFC8415 section 15 */
+ uint32_t lru = arc4random_uniform(
+ state->RTC == 0 ? DHCP6_RAND_MAX
+ : DHCP6_RAND_MAX - DHCP6_RAND_MIN);
+ int lr = (int)lru - (state->RTC == 0 ? 0 : DHCP6_RAND_MAX);
+ RT = state->RT
+ + (unsigned int)((float)state->RT
+ * ((float)lr / DHCP6_RAND_DIV));
+
if (ifp->carrier > LINK_DOWN)
logdebugx("%s: %s %s (xid 0x%02x%02x%02x),"
" next in %0.1f seconds",
state->send->xid[0],
state->send->xid[1],
state->send->xid[2],
- timespec_to_double(&state->RT));
-
- /* This sometimes happens when we delegate to this interface
- * AND run DHCPv6 on it normally. */
- assert(timespec_to_double(&state->RT) != 0);
+ (float)RT / MSEC_PER_SEC);
/* Wait the initial delay */
if (state->IMD != 0) {
state->IMD = 0;
- eloop_timeout_add_tv(ctx->eloop,
- &state->RT, callback, ifp);
+ eloop_timeout_add_msec(ctx->eloop, RT, callback, ifp);
return 0;
}
}
#ifdef PRIVSEP
sent:
#endif
+ state->RT = RT * 2;
+ if (state->RT < RT) /* Check overflow */
+ state->RT = RT;
state->RTC++;
if (callback) {
if (state->MRC == 0 || state->RTC < state->MRC)
- eloop_timeout_add_tv(ctx->eloop,
- &state->RT, callback, ifp);
+ eloop_timeout_add_msec(ctx->eloop,
+ RT, callback, ifp);
else if (state->MRC != 0 && state->MRCcallback)
- eloop_timeout_add_tv(ctx->eloop,
- &state->RT, state->MRCcallback, ifp);
+ eloop_timeout_add_msec(ctx->eloop,
+ RT, state->MRCcallback, ifp);
else
logwarnx("%s: sent %d times with no reply",
ifp->name, state->RTC);
#define IRT_DEFAULT 86400
#define IRT_MINIMUM 600
-#define DHCP6_RAND_MIN -100
-#define DHCP6_RAND_MAX 100
+/* These should give -.1 to .1 randomness */
+#define DHCP6_RAND_MIN -100
+#define DHCP6_RAND_MAX 100
+#define DHCP6_RAND_DIV 1000.0f
enum DH6S {
DH6S_INIT,
enum DH6S state;
struct timespec started;
- /* Message retransmission timings */
- struct timespec RT;
+ /* Message retransmission timings in seconds */
unsigned int IMD;
unsigned int RTC;
- time_t IRT;
+ unsigned int IRT;
unsigned int MRC;
- time_t MRT;
+ unsigned int MRT;
void (*MRCcallback)(void *);
- time_t sol_max_rt;
- time_t inf_max_rt;
+ unsigned int sol_max_rt;
+ unsigned int inf_max_rt;
+ unsigned int RT; /* retransmission timer in milliseconds
+ * maximal RT is 1 day + RAND,
+ * so should be enough */
struct dhcp6_message *send;
size_t send_len;
#endif
#ifndef MSEC_PER_SEC
-#define MSEC_PER_SEC 1000L
+#define MSEC_PER_SEC 1000
#define NSEC_PER_MSEC 1000000L
#define NSEC_PER_SEC 1000000000U
#endif
}
int
-eloop_q_timeout_add_msec(struct eloop *eloop, int queue, long when,
+eloop_q_timeout_add_msec(struct eloop *eloop, int queue, unsigned long when,
void (*callback)(void *), void *arg)
{
- long seconds, nseconds;
+ unsigned long seconds, nseconds;
seconds = when / MSEC_PER_SEC;
if (seconds > UINT_MAX) {
int eloop_q_timeout_add_sec(struct eloop *, int,
unsigned int, void (*)(void *), void *);
int eloop_q_timeout_add_msec(struct eloop *, int,
- long, void (*)(void *), void *);
+ unsigned long, void (*)(void *), void *);
int eloop_q_timeout_delete(struct eloop *, int, void (*)(void *), void *);
int eloop_signal_set_cb(struct eloop *, const int *, size_t,