diff --git a/ndhc/arp.c b/ndhc/arp.c index 20b166e..0fc3b39 100644 --- a/ndhc/arp.c +++ b/ndhc/arp.c @@ -524,7 +524,7 @@ static int arp_gen_probe_wait(void) return PROBE_MIN + rand() % (PROBE_MAX - PROBE_MIN); } -static void arp_defense_timeout(struct client_state_t *cs) +static void arp_defense_timeout(struct client_state_t *cs, long long nowts) { if (pending_def_ts) { log_line("arp: Defending our lease IP."); @@ -538,16 +538,15 @@ static void arp_defense_timeout(struct client_state_t *cs) } } -static void arp_check_timeout(struct client_state_t *cs) +static void arp_check_timeout(struct client_state_t *cs, long long nowts) { - arp_defense_timeout(cs); + arp_defense_timeout(cs, nowts); if (arpState == AS_GW_CHECK && act_if_arp_gw_failed(cs)) return; - long long cms = curms(); long long rtts = arp_send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY; - if (cms < rtts) { - cs->timeout = rtts - cms; + if (nowts < rtts) { + cs->timeout = rtts - nowts; return; } log_line(arpState == AS_GW_CHECK ? @@ -558,20 +557,19 @@ static void arp_check_timeout(struct client_state_t *cs) cs->timeout = ARP_RETRANS_DELAY; } -static void arp_collision_timeout(struct client_state_t *cs) +static void arp_collision_timeout(struct client_state_t *cs, long long nowts) { - arp_defense_timeout(cs); + arp_defense_timeout(cs, nowts); - long long cms = curms(); - if (cms >= collision_check_init_ts + ANNOUNCE_WAIT || + if (nowts >= collision_check_init_ts + ANNOUNCE_WAIT || arp_send_stats[ASEND_COLLISION_CHECK].count >= PROBE_NUM) { arp_success(cs); return; } long long rtts = arp_send_stats[ASEND_COLLISION_CHECK].ts + probe_wait_time; - if (cms < rtts) { - cs->timeout = rtts - cms; + if (nowts < rtts) { + cs->timeout = rtts - nowts; return; } log_line("arp: Probing for hosts that may conflict with our lease..."); @@ -659,7 +657,7 @@ static void arp_do_invalid(struct client_state_t *cs) typedef struct { void (*packet_fn)(struct client_state_t *cs); - void (*timeout_fn)(struct client_state_t *cs); + void (*timeout_fn)(struct client_state_t *cs, long long nowts); } arp_state_fn_t; static const arp_state_fn_t arp_states[] = { @@ -691,7 +689,7 @@ void handle_arp_response(struct client_state_t *cs) } if (r <= 0) { - handle_arp_timeout(cs); + handle_arp_timeout(cs, curms()); return; } @@ -712,8 +710,8 @@ void handle_arp_response(struct client_state_t *cs) } // Perform retransmission if necessary. -void handle_arp_timeout(struct client_state_t *cs) +void handle_arp_timeout(struct client_state_t *cs, long long nowts) { if (arp_states[arpState].timeout_fn) - arp_states[arpState].timeout_fn(cs); + arp_states[arpState].timeout_fn(cs, nowts); } diff --git a/ndhc/arp.h b/ndhc/arp.h index b8ee48e..e101384 100644 --- a/ndhc/arp.h +++ b/ndhc/arp.h @@ -54,6 +54,6 @@ int arp_gw_check(struct client_state_t *cs); void arp_set_defense_mode(struct client_state_t *cs); void arp_success(struct client_state_t *cs); void handle_arp_response(struct client_state_t *cs); -void handle_arp_timeout(struct client_state_t *cs); +void handle_arp_timeout(struct client_state_t *cs, long long nowts); #endif /* ARP_H_ */ diff --git a/ndhc/ndhc.c b/ndhc/ndhc.c index c15b2d7..3f7a643 100644 --- a/ndhc/ndhc.c +++ b/ndhc/ndhc.c @@ -161,7 +161,7 @@ static int get_clientid_mac_string(char *str, size_t slen) static void do_work(void) { struct epoll_event events[3]; - long long last_awake; + long long last_awake, nowts; int timeout_delta; cs.epollFd = epoll_create1(0); @@ -170,10 +170,10 @@ static void do_work(void) setup_signals(&cs); epoll_add(&cs, cs.nlFd); set_listen_raw(&cs); - timeout_action(&cs); + last_awake = curms(); + timeout_action(&cs, last_awake); for (;;) { - last_awake = curms(); int r = epoll_wait(cs.epollFd, events, 3, cs.timeout); if (r == -1) { if (errno == EINTR) @@ -195,12 +195,14 @@ static void do_work(void) suicide("epoll_wait: unknown fd"); } - timeout_delta = curms() - last_awake; + nowts = curms(); + timeout_delta = nowts - last_awake; cs.timeout -= timeout_delta; if (cs.timeout <= 0) { cs.timeout = 0; - timeout_action(&cs); + timeout_action(&cs, nowts); } + last_awake = nowts; } } diff --git a/ndhc/state.c b/ndhc/state.c index cbcac30..669cfe2 100644 --- a/ndhc/state.c +++ b/ndhc/state.c @@ -16,12 +16,12 @@ static void selecting_packet(struct client_state_t *cs, struct dhcpmsg *packet, uint8_t *message); static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet, uint8_t *message); -static void selecting_timeout(struct client_state_t *cs); -static void requesting_timeout(struct client_state_t *cs); -static void bound_timeout(struct client_state_t *cs); -static void renewing_timeout(struct client_state_t *cs); -static void rebinding_timeout(struct client_state_t *cs); -static void released_timeout(struct client_state_t *cs); +static void selecting_timeout(struct client_state_t *cs, long long nowts); +static void requesting_timeout(struct client_state_t *cs, long long nowts); +static void bound_timeout(struct client_state_t *cs, long long nowts); +static void renewing_timeout(struct client_state_t *cs, long long nowts); +static void rebinding_timeout(struct client_state_t *cs, long long nowts); +static void released_timeout(struct client_state_t *cs, long long nowts); static void xmit_release(struct client_state_t *cs); static void print_release(struct client_state_t *cs); static void frenew(struct client_state_t *cs); @@ -29,7 +29,7 @@ static void frenew(struct client_state_t *cs); typedef struct { void (*packet_fn)(struct client_state_t *cs, struct dhcpmsg *packet, uint8_t *message); - void (*timeout_fn)(struct client_state_t *cs); + void (*timeout_fn)(struct client_state_t *cs, long long nowts); void (*force_renew_fn)(struct client_state_t *cs); void (*force_release_fn)(struct client_state_t *cs); } dhcp_state_t; @@ -85,7 +85,7 @@ static void set_released(struct client_state_t *cs) // been received within the response wait time. If we've not exceeded the // maximum number of request retransmits, then send another packet and wait // again. Otherwise, return to the DHCP initialization state. -static void requesting_timeout(struct client_state_t *cs) +static void requesting_timeout(struct client_state_t *cs, long long nowts) { if (num_dhcp_requests < 5) { send_selecting(cs); @@ -97,14 +97,17 @@ static void requesting_timeout(struct client_state_t *cs) // Triggered when the lease has been held for a significant fraction of its // total time, and it is time to renew the lease so that it is not lost. -static void bound_timeout(struct client_state_t *cs) +static void bound_timeout(struct client_state_t *cs, long long nowts) { - if (curms() < cs->leaseStartTime + cs->renewTime * 1000) + long long rnt = cs->leaseStartTime + cs->renewTime * 1000; + if (nowts < rnt) { + cs->timeout = rnt - nowts; return; + } cs->dhcpState = DS_RENEWING; set_listen_cooked(cs); log_line("Entering renew state."); - renewing_timeout(cs); + renewing_timeout(cs, nowts); } static void lease_timedout(struct client_state_t *cs) @@ -119,23 +122,22 @@ static void lease_timedout(struct client_state_t *cs) // expires. Check to see if the lease is still valid, and if it is, send // a unicast DHCP renew packet. If it is not, then change to the REBINDING // state to send broadcast queries. -static void renewing_timeout(struct client_state_t *cs) +static void renewing_timeout(struct client_state_t *cs, long long nowts) { - long long ct = curms(); long long rbt = cs->leaseStartTime + cs->rebindTime * 1000; - if (ct < rbt) { - long long wt = (rbt - ct) / 2; + if (nowts < rbt) { + long long wt = (rbt - nowts) / 2; if (wt >= 30000) send_renew(cs); else - wt = rbt - ct; + wt = rbt - nowts; cs->timeout = wt; return; } long long elt = cs->leaseStartTime + cs->lease * 1000; - if (ct < elt) { + if (nowts < elt) { cs->dhcpState = DS_REBINDING; - cs->timeout = (elt - ct) / 2; + cs->timeout = (elt - nowts) / 2; log_line("Entering rebinding state."); } else lease_timedout(cs); @@ -145,22 +147,21 @@ static void renewing_timeout(struct client_state_t *cs) // received within the response wait time. Check to see if the lease is still // valid, and if it is, send a broadcast DHCP renew packet. If it is not, then // change to the SELECTING state to get a new lease. -static void rebinding_timeout(struct client_state_t *cs) +static void rebinding_timeout(struct client_state_t *cs, long long nowts) { - long long ct = curms(); long long elt = cs->leaseStartTime + cs->lease * 1000; - if (ct < elt) { - long long wt = (elt - ct) / 2; + if (nowts < elt) { + long long wt = (elt - nowts) / 2; if (wt >= 30000) send_rebind(cs); else - wt = elt - ct; + wt = elt - nowts; cs->timeout = wt; } else lease_timedout(cs); } -static void released_timeout(struct client_state_t *cs) +static void released_timeout(struct client_state_t *cs, long long nowts) { cs->timeout = -1; } @@ -233,7 +234,7 @@ static void selecting_packet(struct client_state_t *cs, struct dhcpmsg *packet, // been received within the response wait time. If we've not exceeded the // maximum number of discover retransmits, then send another packet and wait // again. Otherwise, background or fail. -static void selecting_timeout(struct client_state_t *cs) +static void selecting_timeout(struct client_state_t *cs, long long nowts) { if (cs->init && num_dhcp_requests >= 2) { if (client_config.background_if_no_lease) { @@ -315,11 +316,11 @@ void packet_action(struct client_state_t *cs, struct dhcpmsg *packet, dhcp_states[cs->dhcpState].packet_fn(cs, packet, message); } -void timeout_action(struct client_state_t *cs) +void timeout_action(struct client_state_t *cs, long long nowts) { - handle_arp_timeout(cs); if (dhcp_states[cs->dhcpState].timeout_fn) - dhcp_states[cs->dhcpState].timeout_fn(cs); + dhcp_states[cs->dhcpState].timeout_fn(cs, nowts); + handle_arp_timeout(cs, nowts); } void force_renew_action(struct client_state_t *cs) diff --git a/ndhc/state.h b/ndhc/state.h index ecd65d2..feb9654 100644 --- a/ndhc/state.h +++ b/ndhc/state.h @@ -20,7 +20,7 @@ void reinit_selecting(struct client_state_t *cs, int timeout); void packet_action(struct client_state_t *cs, struct dhcpmsg *packet, uint8_t *message); -void timeout_action(struct client_state_t *cs); +void timeout_action(struct client_state_t *cs, long long nowts); void force_renew_action(struct client_state_t *cs); void force_release_action(struct client_state_t *cs);