diff --git a/ndhc/arp.c b/ndhc/arp.c index ce7086e..1ec17c6 100644 --- a/ndhc/arp.c +++ b/ndhc/arp.c @@ -30,6 +30,7 @@ #include #include #include "arp.h" +#include "state.h" #include "packet.h" #include "sys.h" #include "ifchange.h" @@ -180,7 +181,7 @@ static void arp_failed(struct client_state_t *cs) if (cs->arpPrevState != DS_REQUESTING) ifchange(NULL, IFCHANGE_DECONFIG); - cs->dhcpState = DS_INIT_SELECTING; + cs->dhcpState = DS_SELECTING; cs->requestedIP = 0; cs->timeout = 0; cs->packetNum = 0; @@ -194,7 +195,7 @@ void arp_gw_failed(struct client_state_t *cs) // Same as packet.c: line 258 ifchange(NULL, IFCHANGE_DECONFIG); - cs->dhcpState = DS_INIT_SELECTING; + cs->dhcpState = DS_SELECTING; cs->oldTimeout = 0; cs->timeout = 0; cs->requestedIP = 0; diff --git a/ndhc/config.h b/ndhc/config.h index cc19d2b..ddfec54 100644 --- a/ndhc/config.h +++ b/ndhc/config.h @@ -26,19 +26,6 @@ #define NUMPACKETS 3 /* number of packets to send before delay */ #define RETRY_DELAY 30 /* time in seconds to delay after sending NUMPACKETS */ -enum { - DS_NULL = 0, - DS_INIT_SELECTING, - DS_REQUESTING, - DS_BOUND, - DS_RENEWING, - DS_REBINDING, - DS_ARP_GW_CHECK, - DS_ARP_CHECK, - DS_RENEW_REQUESTED, - DS_RELEASED -}; - enum { LM_NONE = 0, LM_KERNEL, diff --git a/ndhc/ndhc.c b/ndhc/ndhc.c index 12ae5bf..f351858 100644 --- a/ndhc/ndhc.c +++ b/ndhc/ndhc.c @@ -25,12 +25,12 @@ #include #include #include -#include -#include -#include #include #include #include +#include +#include +#include #include #include #include @@ -40,9 +40,9 @@ #include "ndhc-defines.h" #include "config.h" +#include "state.h" #include "options.h" #include "packet.h" -#include "timeout.h" #include "sys.h" #include "ifchange.h" #include "arp.h" @@ -60,8 +60,8 @@ #define VERSION "1.0" struct client_state_t cs = { - .dhcpState = DS_INIT_SELECTING, - .arpPrevState = DS_NULL, + .dhcpState = DS_SELECTING, + .arpPrevState = DS_SELECTING, .ifsPrevState = IFS_NONE, .listenMode = LM_NONE, .packetNum = 0, @@ -120,72 +120,6 @@ static void show_usage(void) exit(EXIT_SUCCESS); } -/* perform a renew */ -static void force_renew(void) -{ - log_line("Performing a DHCP renew..."); - retry: - switch (cs.dhcpState) { - case DS_BOUND: - change_listen_mode(&cs, LM_KERNEL); - case DS_ARP_CHECK: - // Cancel arp ping in progress and treat as previous state. - epoll_del(&cs, cs.arpFd); - close(cs.arpFd); - cs.arpFd = -1; - cs.dhcpState = cs.arpPrevState; - goto retry; - case DS_RENEWING: - case DS_REBINDING: - cs.dhcpState = DS_RENEW_REQUESTED; - break; - case DS_RENEW_REQUESTED: /* impatient are we? fine, square 1 */ - ifchange(NULL, IFCHANGE_DECONFIG); - case DS_REQUESTING: - case DS_RELEASED: - change_listen_mode(&cs, LM_RAW); - cs.dhcpState = DS_INIT_SELECTING; - break; - case DS_INIT_SELECTING: - default: - break; - } - - /* start things over */ - cs.packetNum = 0; - - /* Kill any timeouts because the user wants this to hurry along */ - cs.timeout = 0; -} - - -/* perform a release */ -static void force_release(void) -{ - struct in_addr temp_saddr, temp_raddr; - - /* send release packet */ - if (cs.dhcpState == DS_BOUND || cs.dhcpState == DS_RENEWING || - cs.dhcpState == DS_REBINDING || cs.dhcpState == DS_ARP_CHECK) { - temp_saddr.s_addr = cs.serverAddr; - temp_raddr.s_addr = cs.requestedIP; - log_line("Unicasting a release of %s to %s.", - inet_ntoa(temp_raddr), inet_ntoa(temp_saddr)); - send_release(cs.serverAddr, cs.requestedIP); /* unicast */ - ifchange(NULL, IFCHANGE_DECONFIG); - } - log_line("Entering released state."); - - if (cs.dhcpState == DS_ARP_CHECK) { - epoll_del(&cs, cs.arpFd); - close(cs.arpFd); - cs.arpFd = -1; - } - change_listen_mode(&cs, LM_NONE); - cs.dhcpState = DS_RELEASED; - cs.timeout = -1; -} - static void signal_dispatch() { int t, off = 0; @@ -203,10 +137,10 @@ static void signal_dispatch() } switch (si.ssi_signo) { case SIGUSR1: - force_renew(); + force_renew_action(&cs); break; case SIGUSR2: - force_release(); + force_release_action(&cs); break; case SIGTERM: log_line("Received SIGTERM. Exiting gracefully."); @@ -228,7 +162,7 @@ static void do_work(void) setup_signals(&cs); epoll_add(&cs, cs.nlFd); change_listen_mode(&cs, LM_RAW); - handle_timeout(&cs); + timeout_action(&cs); for (;;) { last_awake = curms(); @@ -257,7 +191,7 @@ static void do_work(void) cs.timeout -= timeout_delta; if (cs.timeout <= 0) { cs.timeout = 0; - handle_timeout(&cs); + timeout_action(&cs); } } } diff --git a/ndhc/netlink.c b/ndhc/netlink.c index 694b7ee..794411f 100644 --- a/ndhc/netlink.c +++ b/ndhc/netlink.c @@ -113,7 +113,7 @@ static void takedown_if(struct client_state_t *cs) log_line("nl: taking down interface"); // Same as packet.c: line 258 ifchange(NULL, IFCHANGE_DECONFIG); - cs->dhcpState = DS_INIT_SELECTING; + cs->dhcpState = DS_SELECTING; cs->timeout = 0; cs->requestedIP = 0; cs->packetNum = 0; @@ -157,7 +157,7 @@ static void nl_handlemsg(struct nlmsghdr *msg, unsigned int len, if (cs->dhcpState == DS_BOUND) { if (arp_gw_check(cs) == -1) log_warning("arp_gw_check could not make arp socket, assuming lease is still OK"); - } else if (cs->dhcpState != DS_INIT_SELECTING) + } else if (cs->dhcpState != DS_SELECTING) takedown_if(cs); } } else { diff --git a/ndhc/netlink.h b/ndhc/netlink.h index 57dae56..6a1ed87 100644 --- a/ndhc/netlink.h +++ b/ndhc/netlink.h @@ -23,7 +23,7 @@ #ifndef NK_NETLINK_H_ #define NK_NETLINK_H_ -#include "config.h" +#include "state.h" int nl_open(struct client_state_t *cs); void nl_close(struct client_state_t *cs); diff --git a/ndhc/packet.c b/ndhc/packet.c index c14692e..3529111 100644 --- a/ndhc/packet.c +++ b/ndhc/packet.c @@ -39,6 +39,7 @@ #include #include "packet.h" +#include "state.h" #include "arp.h" #include "ifchange.h" #include "sys.h" @@ -470,69 +471,6 @@ void change_listen_mode(struct client_state_t *cs, int new_mode) new_mode == LM_RAW ? "raw" : "cooked"); } -static void init_selecting_packet(struct client_state_t *cs, - struct dhcpmsg *packet, - uint8_t *message) -{ - uint8_t *temp = NULL; - ssize_t optlen; - if (*message == DHCPOFFER) { - if ((temp = get_option_data(packet, DHCP_SERVER_ID, &optlen))) { - memcpy(&cs->serverAddr, temp, 4); - cs->xid = packet->xid; - cs->requestedIP = packet->yiaddr; - cs->dhcpState = DS_REQUESTING; - cs->timeout = 0; - cs->packetNum = 0; - } else { - log_line("No server ID in message"); - } - } -} - -static void dhcp_ack_or_nak_packet(struct client_state_t *cs, - struct dhcpmsg *packet, - uint8_t *message) -{ - uint8_t *temp = NULL; - ssize_t optlen; - if (*message == DHCPACK) { - if (!(temp = get_option_data(packet, DHCP_LEASE_TIME, &optlen))) { - log_line("No lease time received, assuming 1h."); - cs->lease = 60 * 60; - } else { - memcpy(&cs->lease, temp, 4); - cs->lease = ntohl(cs->lease); - // Enforce upper and lower bounds on lease. - cs->lease &= 0x0fffffff; - if (cs->lease < RETRY_DELAY) - cs->lease = RETRY_DELAY; - } - - // Can transition from DS_ARP_CHECK to DS_BOUND or DS_INIT_SELECTING. - if (arp_check(cs, packet) == -1) { - log_warning("arp_check failed to make arp socket, retrying lease"); - ifchange(NULL, IFCHANGE_DECONFIG); - cs->dhcpState = DS_INIT_SELECTING; - cs->timeout = 30000; - cs->requestedIP = 0; - cs->packetNum = 0; - change_listen_mode(cs, LM_RAW); - } - - } else if (*message == DHCPNAK) { - log_line("Received DHCP NAK."); - ifchange(packet, IFCHANGE_NAK); - if (cs->dhcpState != DS_REQUESTING) - ifchange(NULL, IFCHANGE_DECONFIG); - cs->dhcpState = DS_INIT_SELECTING; - cs->timeout = 3000; - cs->requestedIP = 0; - cs->packetNum = 0; - change_listen_mode(cs, LM_RAW); - } -} - void handle_packet(struct client_state_t *cs) { uint8_t *message = NULL; @@ -578,25 +516,7 @@ void handle_packet(struct client_state_t *cs) return; } - switch (cs->dhcpState) { - case DS_INIT_SELECTING: - init_selecting_packet(cs, &packet, message); - break; - case DS_ARP_CHECK: - // We ignore dhcp packets for now. This state will - // be changed by the callback for arp ping. - break; - case DS_RENEW_REQUESTED: - case DS_REQUESTING: - case DS_RENEWING: - case DS_REBINDING: - dhcp_ack_or_nak_packet(cs, &packet, message); - break; - case DS_BOUND: - case DS_RELEASED: - default: - break; - } + packet_action(cs, &packet, message); } // Initialize a DHCP client packet that will be sent to a server diff --git a/ndhc/state.c b/ndhc/state.c new file mode 100644 index 0000000..624a7b8 --- /dev/null +++ b/ndhc/state.c @@ -0,0 +1,314 @@ +#include +#include +#include +#include +#include +#include +#include "state.h" +#include "ifchange.h" +#include "arp.h" +#include "options.h" +#include "log.h" +#include "sys.h" +#include "random.h" + +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 renew_requested_timeout(struct client_state_t *cs); +static void released_timeout(struct client_state_t *cs); +static void nfrelease(struct client_state_t *cs); +static void frelease(struct client_state_t *cs); +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 (*force_renew_fn)(struct client_state_t *cs); + void (*force_release_fn)(struct client_state_t *cs); +} dhcp_state_t; + +// packet, timeout, renew, release +dhcp_state_t dhcp_states[] = { + { selecting_packet, selecting_timeout, 0, frelease}, // SELECTING + { an_packet, requesting_timeout, frenew, frelease}, // REQUESTING + { 0, bound_timeout, frenew, nfrelease}, // BOUND + { an_packet, renewing_timeout, frenew, nfrelease}, // RENEWING + { an_packet, rebinding_timeout, frenew, nfrelease}, // REBINDING + { 0, arp_gw_failed, frenew, frelease}, // ARP_GW_CHECK XXX + { 0, arp_success, frenew, nfrelease}, // ARP_CHECK + { an_packet, renew_requested_timeout, frenew, frelease}, // RENEW_REQUESTED + { 0, released_timeout, frenew, frelease}, // RELEASED + { 0, 0, 0, 0}, // NUM_STATES +}; + +// Triggered after a DHCP lease request packet has been sent and no reply has +// 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) +{ + if (cs->packetNum < NUMPACKETS) { + send_selecting(cs->xid, cs->serverAddr, cs->requestedIP); + cs->timeout = ((cs->packetNum == NUMPACKETS - 1) ? 10 : 2) * 1000; + cs->packetNum++; + } else { + cs->dhcpState = DS_SELECTING; + cs->timeout = 0; + cs->packetNum = 0; + change_listen_mode(cs, LM_RAW); + } +} + +// 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) +{ + cs->dhcpState = DS_RENEWING; + change_listen_mode(cs, LM_KERNEL); + log_line("Entering renew state."); + renewing_timeout(cs); +} + +// Triggered when a DHCP renew request has been sent and no reply has been +// received within the response wait time. This function is also directly +// called by bound_timeout() when it is time to renew a lease before it +// 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 get a new lease. +static void renewing_timeout(struct client_state_t *cs) +{ + if ((cs->t2 - cs->t1) <= (cs->lease / 14400 + 1)) { + cs->dhcpState = DS_REBINDING; + cs->timeout = (cs->t2 - cs->t1) * 1000; + log_line("Entering rebinding state."); + } else { + send_renew(cs->xid, cs->serverAddr, cs->requestedIP); + cs->t1 = ((cs->t2 - cs->t1) >> 1) + cs->t1; + cs->timeout = (cs->t1 * 1000) - (curms() - cs->leaseStartTime); + } +} + +static void rebinding_timeout(struct client_state_t *cs) +{ + /* Either set a new T2, or enter INIT state */ + if ((cs->lease - cs->t2) <= (cs->lease / 14400 + 1)) { + /* timed out, enter init state */ + cs->dhcpState = DS_SELECTING; + log_line("Lease lost, entering init state."); + ifchange(NULL, IFCHANGE_DECONFIG); + cs->timeout = 0; + cs->packetNum = 0; + change_listen_mode(cs, LM_RAW); + } else { + /* send a request packet */ + send_renew(cs->xid, 0, cs->requestedIP); /* broadcast */ + + cs->t2 = ((cs->lease - cs->t2) >> 1) + cs->t2; + cs->timeout = (cs->t2 * 1000) - (curms() - cs->leaseStartTime); + } +} + +static void renew_requested_timeout(struct client_state_t *cs) +{ + if (cs->packetNum < NUMPACKETS) { + /* send unicast request packet */ + send_renew(cs->xid, cs->serverAddr, cs->requestedIP); + cs->timeout = ((cs->packetNum == NUMPACKETS - 1) ? 10 : 2) * 1000; + cs->packetNum++; + } else { + ifchange(NULL, IFCHANGE_DECONFIG); + cs->dhcpState = DS_SELECTING; + cs->timeout = 0; + cs->packetNum = 0; + change_listen_mode(cs, LM_RAW); + } +} + +static void released_timeout(struct client_state_t *cs) +{ + cs->timeout = -1; +} + +static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet, + uint8_t *message) +{ + uint8_t *temp = NULL; + ssize_t optlen; + if (*message == DHCPACK) { + if (!(temp = get_option_data(packet, DHCP_LEASE_TIME, &optlen))) { + log_line("No lease time received, assuming 1h."); + cs->lease = 60 * 60; + } else { + memcpy(&cs->lease, temp, 4); + cs->lease = ntohl(cs->lease); + // Enforce upper and lower bounds on lease. + cs->lease &= 0x0fffffff; + if (cs->lease < RETRY_DELAY) + cs->lease = RETRY_DELAY; + } + + // Can transition from DS_ARP_CHECK to DS_BOUND or DS_SELECTING. + if (arp_check(cs, packet) == -1) { + log_warning("arp_check failed to make arp socket, retrying lease"); + ifchange(NULL, IFCHANGE_DECONFIG); + cs->dhcpState = DS_SELECTING; + cs->timeout = 30000; + cs->requestedIP = 0; + cs->packetNum = 0; + change_listen_mode(cs, LM_RAW); + } + + } else if (*message == DHCPNAK) { + log_line("Received DHCP NAK."); + ifchange(packet, IFCHANGE_NAK); + if (cs->dhcpState != DS_REQUESTING) + ifchange(NULL, IFCHANGE_DECONFIG); + cs->dhcpState = DS_SELECTING; + cs->timeout = 3000; + cs->requestedIP = 0; + cs->packetNum = 0; + change_listen_mode(cs, LM_RAW); + } +} + +static void selecting_packet(struct client_state_t *cs, struct dhcpmsg *packet, + uint8_t *message) +{ + uint8_t *temp = NULL; + ssize_t optlen; + if (*message == DHCPOFFER) { + if ((temp = get_option_data(packet, DHCP_SERVER_ID, &optlen))) { + memcpy(&cs->serverAddr, temp, 4); + cs->xid = packet->xid; + cs->requestedIP = packet->yiaddr; + cs->dhcpState = DS_REQUESTING; + cs->timeout = 0; + cs->packetNum = 0; + } else { + log_line("No server ID in message"); + } + } +} + +#define DELAY_SEC (((RETRY_DELAY - (RETRY_DELAY / NUMPACKETS)) / NUMPACKETS) + 1) +// Triggered after a DHCP discover packet has been sent and no reply has +// 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) +{ + if (cs->packetNum < NUMPACKETS) { + if (cs->packetNum == 0) + cs->xid = libc_random_u32(); + send_discover(cs->xid, cs->requestedIP); + cs->timeout = DELAY_SEC * (cs->packetNum + 1) * 1000; + cs->packetNum++; + } else { + if (cs->init) { + if (client_config.background_if_no_lease) { + log_line("No lease, going to background."); + cs->init = 0; + background(cs); + } else if (client_config.abort_if_no_lease) { + log_line("No lease, failing."); + exit(EXIT_FAILURE); + } + } + cs->packetNum = 0; + cs->timeout = RETRY_DELAY * 1000; + } +} +#undef DELAY_SEC + +static void nfrelease(struct client_state_t *cs) +{ + struct in_addr temp_saddr = { .s_addr = cs->serverAddr }; + struct in_addr temp_raddr = { .s_addr = cs->requestedIP }; + log_line("Unicasting a release of %s to %s.", + inet_ntoa(temp_raddr), inet_ntoa(temp_saddr)); + send_release(cs->serverAddr, cs->requestedIP); + ifchange(NULL, IFCHANGE_DECONFIG); + frelease(cs); +} + +static void frelease(struct client_state_t *cs) +{ + log_line("Entering released state."); + if (cs->dhcpState == DS_ARP_CHECK) { + epoll_del(cs, cs->arpFd); + close(cs->arpFd); + cs->arpFd = -1; + } + change_listen_mode(cs, LM_NONE); + cs->dhcpState = DS_RELEASED; + cs->timeout = -1; +} + +// XXX: DS_ARP_CHECK_GW? Also split this up? +static void frenew(struct client_state_t *cs) +{ + log_line("Performing a DHCP renew..."); + retry: + switch (cs->dhcpState) { + case DS_BOUND: + change_listen_mode(cs, LM_KERNEL); + case DS_ARP_CHECK: + // Cancel arp ping in progress and treat as previous state. + epoll_del(cs, cs->arpFd); + close(cs->arpFd); + cs->arpFd = -1; + cs->dhcpState = cs->arpPrevState; + goto retry; + case DS_RENEWING: + case DS_REBINDING: + cs->dhcpState = DS_RENEW_REQUESTED; + break; + case DS_RENEW_REQUESTED: /* impatient are we? fine, square 1 */ + ifchange(NULL, IFCHANGE_DECONFIG); + case DS_REQUESTING: + case DS_RELEASED: + change_listen_mode(cs, LM_RAW); + cs->dhcpState = DS_SELECTING; + break; + case DS_SELECTING: + default: + break; + } + // Start over + cs->packetNum = 0; + cs->timeout = 0; +} + +void packet_action(struct client_state_t *cs, struct dhcpmsg *packet, + uint8_t *message) +{ + if (dhcp_states[cs->dhcpState].packet_fn) + dhcp_states[cs->dhcpState].packet_fn(cs, packet, message); +} + +void timeout_action(struct client_state_t *cs) +{ + if (dhcp_states[cs->dhcpState].timeout_fn) + dhcp_states[cs->dhcpState].timeout_fn(cs); +} + +void force_renew_action(struct client_state_t *cs) +{ + if (dhcp_states[cs->dhcpState].force_renew_fn) + dhcp_states[cs->dhcpState].force_renew_fn(cs); +} + +void force_release_action(struct client_state_t *cs) +{ + if (dhcp_states[cs->dhcpState].force_release_fn) + dhcp_states[cs->dhcpState].force_release_fn(cs); +} + diff --git a/ndhc/state.h b/ndhc/state.h new file mode 100644 index 0000000..512cd9d --- /dev/null +++ b/ndhc/state.h @@ -0,0 +1,26 @@ +#ifndef NDHC_STATE_H_ +#define NDHC_STATE_H_ + +#include "config.h" +#include "packet.h" + +typedef enum { + DS_SELECTING = 0, + DS_REQUESTING, + DS_BOUND, + DS_RENEWING, + DS_REBINDING, + DS_ARP_GW_CHECK, + DS_ARP_CHECK, + DS_RENEW_REQUESTED, + DS_RELEASED, + DS_NUM_STATES, +} dhcp_states_t; + +void packet_action(struct client_state_t *cs, struct dhcpmsg *packet, + uint8_t *message); +void timeout_action(struct client_state_t *cs); +void force_renew_action(struct client_state_t *cs); +void force_release_action(struct client_state_t *cs); +#endif + diff --git a/ndhc/timeout.c b/ndhc/timeout.c deleted file mode 100644 index 32ec0a1..0000000 --- a/ndhc/timeout.c +++ /dev/null @@ -1,160 +0,0 @@ -/* timeout.c - callbacks to react to event timeouts - * Time-stamp: <2011-06-11 11:13:22 njk> - * - * (c) 2004-2011 Nicholas J. Kain - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#include "timeout.h" -#include "config.h" -#include "ifchange.h" -#include "packet.h" -#include "arp.h" -#include "log.h" -#include "random.h" - -#define DELAY_SEC (((RETRY_DELAY - (RETRY_DELAY / NUMPACKETS)) / NUMPACKETS) + 1) -// Triggered after a DHCP discover packet has been sent and no reply has -// 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 init_selecting_timeout(struct client_state_t *cs) -{ - if (cs->packetNum < NUMPACKETS) { - if (cs->packetNum == 0) - cs->xid = libc_random_u32(); - send_discover(cs->xid, cs->requestedIP); - cs->timeout = DELAY_SEC * (cs->packetNum + 1) * 1000; - cs->packetNum++; - } else { - if (cs->init) { - if (client_config.background_if_no_lease) { - log_line("No lease, going to background."); - cs->init = 0; - background(cs); - } else if (client_config.abort_if_no_lease) { - log_line("No lease, failing."); - exit(EXIT_FAILURE); - } - } - cs->packetNum = 0; - cs->timeout = RETRY_DELAY * 1000; - } -} -#undef DELAY_SEC - -static void renew_requested_timeout(struct client_state_t *cs) -{ - if (cs->packetNum < NUMPACKETS) { - /* send unicast request packet */ - send_renew(cs->xid, cs->serverAddr, cs->requestedIP); - cs->timeout = ((cs->packetNum == NUMPACKETS - 1) ? 10 : 2) * 1000; - cs->packetNum++; - } else { - ifchange(NULL, IFCHANGE_DECONFIG); - cs->dhcpState = DS_INIT_SELECTING; - cs->timeout = 0; - cs->packetNum = 0; - change_listen_mode(cs, LM_RAW); - } -} - -// Triggered after a DHCP lease request packet has been sent and no reply has -// 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) -{ - if (cs->packetNum < NUMPACKETS) { - send_selecting(cs->xid, cs->serverAddr, cs->requestedIP); - cs->timeout = ((cs->packetNum == NUMPACKETS - 1) ? 10 : 2) * 1000; - cs->packetNum++; - } else { - cs->dhcpState = DS_INIT_SELECTING; - cs->timeout = 0; - cs->packetNum = 0; - change_listen_mode(cs, LM_RAW); - } -} - -// Triggered when a DHCP renew request has been sent and no reply has been -// received within the response wait time. This function is also directly -// called by bound_timeout() when it is time to renew a lease before it -// 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 get a new lease. -static void renewing_timeout(struct client_state_t *cs) -{ - if ((cs->t2 - cs->t1) <= (cs->lease / 14400 + 1)) { - cs->dhcpState = DS_REBINDING; - cs->timeout = (cs->t2 - cs->t1) * 1000; - log_line("Entering rebinding state."); - } else { - send_renew(cs->xid, cs->serverAddr, cs->requestedIP); - cs->t1 = ((cs->t2 - cs->t1) >> 1) + cs->t1; - cs->timeout = (cs->t1 * 1000) - (curms() - cs->leaseStartTime); - } -} - -// 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) -{ - cs->dhcpState = DS_RENEWING; - change_listen_mode(cs, LM_KERNEL); - log_line("Entering renew state."); - renewing_timeout(cs); -} - -static void rebinding_timeout(struct client_state_t *cs) -{ - /* Either set a new T2, or enter INIT state */ - if ((cs->lease - cs->t2) <= (cs->lease / 14400 + 1)) { - /* timed out, enter init state */ - cs->dhcpState = DS_INIT_SELECTING; - log_line("Lease lost, entering init state."); - ifchange(NULL, IFCHANGE_DECONFIG); - cs->timeout = 0; - cs->packetNum = 0; - change_listen_mode(cs, LM_RAW); - } else { - /* send a request packet */ - send_renew(cs->xid, 0, cs->requestedIP); /* broadcast */ - - cs->t2 = ((cs->lease - cs->t2) >> 1) + cs->t2; - cs->timeout = (cs->t2 * 1000) - (curms() - cs->leaseStartTime); - } -} - -// Handle epoll timeout expiring -void handle_timeout(struct client_state_t *cs) -{ - switch (cs->dhcpState) { - case DS_INIT_SELECTING: init_selecting_timeout(cs); break; - case DS_RENEW_REQUESTED: renew_requested_timeout(cs); break; - case DS_REQUESTING: requesting_timeout(cs); break; - case DS_RENEWING: renewing_timeout(cs); break; - case DS_BOUND: bound_timeout(cs); break; - case DS_REBINDING: rebinding_timeout(cs); break; - case DS_RELEASED: cs->timeout = -1; break; - case DS_ARP_CHECK: arp_success(cs); break; - case DS_ARP_GW_CHECK: arp_gw_failed(cs); break; - default: break; - } -} diff --git a/ndhc/timeout.h b/ndhc/timeout.h deleted file mode 100644 index 7867f52..0000000 --- a/ndhc/timeout.h +++ /dev/null @@ -1,29 +0,0 @@ -/* timeout.h - callbacks to react to event timeouts - * Time-stamp: <2011-03-30 23:42:25 nk> - * - * (c) 2004-2011 Nicholas J. Kain - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef TIMEOUT_H_ -#define TIMEOUT_H_ - -#include "config.h" -#include "sys.h" - -void handle_timeout(struct client_state_t *cs); - -#endif /* TIMEOUT_H_ */