Split state machine apart into functions.
This commit is contained in:
parent
6772ddac1b
commit
406e316274
308
ndhc/ndhc.c
308
ndhc/ndhc.c
@ -321,11 +321,8 @@ static void arp_success(void)
|
|||||||
background();
|
background();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle select timeout dropping to zero */
|
static void init_selecting_timeout()
|
||||||
static void handle_timeout(void)
|
|
||||||
{
|
{
|
||||||
switch (dhcp_state) {
|
|
||||||
case INIT_SELECTING:
|
|
||||||
if (packet_num < NUMPACKETS) {
|
if (packet_num < NUMPACKETS) {
|
||||||
if (packet_num == 0)
|
if (packet_num == 0)
|
||||||
xid = random_xid();
|
xid = random_xid();
|
||||||
@ -346,36 +343,43 @@ static void handle_timeout(void)
|
|||||||
packet_num = 0;
|
packet_num = 0;
|
||||||
timeout = RETRY_DELAY * 1000;
|
timeout = RETRY_DELAY * 1000;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case RENEW_REQUESTED:
|
|
||||||
case REQUESTING:
|
static void renew_requested_timeout()
|
||||||
|
{
|
||||||
if (packet_num < NUMPACKETS) {
|
if (packet_num < NUMPACKETS) {
|
||||||
/* send request packet */
|
/* send unicast request packet */
|
||||||
if (dhcp_state == RENEW_REQUESTED)
|
|
||||||
/* unicast */
|
|
||||||
send_renew(xid, server_addr, requested_ip);
|
send_renew(xid, server_addr, requested_ip);
|
||||||
else
|
|
||||||
/* broadcast */
|
|
||||||
send_selecting(xid, server_addr, requested_ip);
|
|
||||||
timeout = ((packet_num == NUMPACKETS - 1) ? 10 : 2) * 1000;
|
timeout = ((packet_num == NUMPACKETS - 1) ? 10 : 2) * 1000;
|
||||||
packet_num++;
|
packet_num++;
|
||||||
} else {
|
} else {
|
||||||
/* timed out, go back to init state */
|
/* timed out, go back to init state */
|
||||||
if (dhcp_state == RENEW_REQUESTED)
|
|
||||||
run_script(NULL, SCRIPT_DECONFIG);
|
run_script(NULL, SCRIPT_DECONFIG);
|
||||||
dhcp_state = INIT_SELECTING;
|
dhcp_state = INIT_SELECTING;
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
packet_num = 0;
|
packet_num = 0;
|
||||||
change_listen_mode(LISTEN_RAW);
|
change_listen_mode(LISTEN_RAW);
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case BOUND:
|
|
||||||
/* Lease is starting to run out, time to enter renewing state */
|
static void requesting_timeout()
|
||||||
dhcp_state = RENEWING;
|
{
|
||||||
change_listen_mode(LISTEN_KERNEL);
|
if (packet_num < NUMPACKETS) {
|
||||||
log_line("Entering renew state.");
|
/* send broadcast request packet */
|
||||||
/* fall right through */
|
send_selecting(xid, server_addr, requested_ip);
|
||||||
case RENEWING:
|
timeout = ((packet_num == NUMPACKETS - 1) ? 10 : 2) * 1000;
|
||||||
|
packet_num++;
|
||||||
|
} else {
|
||||||
|
/* timed out, go back to init state */
|
||||||
|
dhcp_state = INIT_SELECTING;
|
||||||
|
timeout = 0;
|
||||||
|
packet_num = 0;
|
||||||
|
change_listen_mode(LISTEN_RAW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renewing_timeout()
|
||||||
|
{
|
||||||
/* Either set a new T1, or enter REBINDING state */
|
/* Either set a new T1, or enter REBINDING state */
|
||||||
if ((t2 - t1) <= (lease / 14400 + 1)) {
|
if ((t2 - t1) <= (lease / 14400 + 1)) {
|
||||||
/* timed out, enter rebinding state */
|
/* timed out, enter rebinding state */
|
||||||
@ -389,8 +393,19 @@ static void handle_timeout(void)
|
|||||||
t1 = ((t2 - t1) >> 1) + t1;
|
t1 = ((t2 - t1) >> 1) + t1;
|
||||||
timeout = (t1 * 1000) - (curms() - start);
|
timeout = (t1 * 1000) - (curms() - start);
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case REBINDING:
|
|
||||||
|
static void bound_timeout()
|
||||||
|
{
|
||||||
|
/* Lease is starting to run out, time to enter renewing state */
|
||||||
|
dhcp_state = RENEWING;
|
||||||
|
change_listen_mode(LISTEN_KERNEL);
|
||||||
|
log_line("Entering renew state.");
|
||||||
|
renewing_timeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rebinding_timeout()
|
||||||
|
{
|
||||||
/* Either set a new T2, or enter INIT state */
|
/* Either set a new T2, or enter INIT state */
|
||||||
if ((lease - t2) <= (lease / 14400 + 1)) {
|
if ((lease - t2) <= (lease / 14400 + 1)) {
|
||||||
/* timed out, enter init state */
|
/* timed out, enter init state */
|
||||||
@ -407,14 +422,140 @@ static void handle_timeout(void)
|
|||||||
t2 = ((lease - t2) >> 1) + t2;
|
t2 = ((lease - t2) >> 1) + t2;
|
||||||
timeout = (t2 * 1000) - (curms() - start);
|
timeout = (t2 * 1000) - (curms() - start);
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case RELEASED:
|
|
||||||
/* yah, I know, *you* say it would never happen */
|
/* Handle epoll timeout expiring */
|
||||||
timeout = -1;
|
static void handle_timeout(void)
|
||||||
|
{
|
||||||
|
switch (dhcp_state) {
|
||||||
|
case INIT_SELECTING: init_selecting_timeout(); break;
|
||||||
|
case RENEW_REQUESTED: renew_requested_timeout(); break;
|
||||||
|
case REQUESTING: requesting_timeout(); break;
|
||||||
|
case RENEWING: renewing_timeout(); break;
|
||||||
|
case BOUND: bound_timeout(); break;
|
||||||
|
case REBINDING: rebinding_timeout(); break;
|
||||||
|
case RELEASED: timeout = -1; break;
|
||||||
|
case ARP_CHECK: arp_success(); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_selecting_packet(struct dhcpMessage *packet,
|
||||||
|
unsigned char *message)
|
||||||
|
{
|
||||||
|
unsigned char *temp = NULL;
|
||||||
|
/* Must be a DHCPOFFER to one of our xid's */
|
||||||
|
if (*message == DHCPOFFER) {
|
||||||
|
if ((temp = get_option(packet, DHCP_SERVER_ID))) {
|
||||||
|
/* Memcpy to a temp buffer to force alignment */
|
||||||
|
memcpy(&server_addr, temp, 4);
|
||||||
|
xid = packet->xid;
|
||||||
|
requested_ip = packet->yiaddr;
|
||||||
|
|
||||||
|
/* enter requesting state */
|
||||||
|
dhcp_state = REQUESTING;
|
||||||
|
timeout = 0;
|
||||||
|
packet_num = 0;
|
||||||
|
} else {
|
||||||
|
log_line("No server ID in message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dhcp_ack_or_nak_packet(struct dhcpMessage *packet,
|
||||||
|
unsigned char *message)
|
||||||
|
{
|
||||||
|
unsigned char *temp = NULL;
|
||||||
|
if (*message == DHCPACK) {
|
||||||
|
if (!(temp = get_option(packet, DHCP_LEASE_TIME))) {
|
||||||
|
log_line("No lease time received, assuming 1h.");
|
||||||
|
lease = 60 * 60;
|
||||||
|
} else {
|
||||||
|
/* Memcpy to a temp buffer to force alignment */
|
||||||
|
memcpy(&lease, temp, 4);
|
||||||
|
lease = ntohl(lease);
|
||||||
|
/* Enforce upper and lower bounds on lease. */
|
||||||
|
lease &= 0x0fffffff;
|
||||||
|
if (lease < RETRY_DELAY)
|
||||||
|
lease = RETRY_DELAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
arp_prev_dhcp_state = dhcp_state;
|
||||||
|
dhcp_state = ARP_CHECK;
|
||||||
|
memcpy(&arp_dhcp_packet, packet, sizeof (struct dhcpMessage));
|
||||||
|
arpFd = arpping(arp_dhcp_packet.yiaddr, NULL, 0,
|
||||||
|
client_config.arp, client_config.interface);
|
||||||
|
epoll_add(arpFd);
|
||||||
|
timeout = 2000;
|
||||||
|
memset(&arpreply, 0, sizeof arpreply);
|
||||||
|
arpreply_offset = 0;
|
||||||
|
// Can transition to BOUND or INIT_SELECTING.
|
||||||
|
|
||||||
|
} else if (*message == DHCPNAK) {
|
||||||
|
/* return to init state */
|
||||||
|
log_line("Received DHCP NAK.");
|
||||||
|
run_script(packet, SCRIPT_NAK);
|
||||||
|
if (dhcp_state != REQUESTING)
|
||||||
|
run_script(NULL, SCRIPT_DECONFIG);
|
||||||
|
dhcp_state = INIT_SELECTING;
|
||||||
|
timeout = 0;
|
||||||
|
requested_ip = 0;
|
||||||
|
packet_num = 0;
|
||||||
|
change_listen_mode(LISTEN_RAW);
|
||||||
|
// XXX: this isn't rfc compliant: should be exp backoff
|
||||||
|
sleep(3); /* avoid excessive network traffic */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_packet(void)
|
||||||
|
{
|
||||||
|
unsigned char *message = NULL;
|
||||||
|
int len;
|
||||||
|
struct dhcpMessage packet;
|
||||||
|
|
||||||
|
if (listen_mode == LISTEN_KERNEL)
|
||||||
|
len = get_packet(&packet, listenFd);
|
||||||
|
else if (listen_mode == LISTEN_RAW)
|
||||||
|
len = get_raw_packet(&packet, listenFd);
|
||||||
|
else /* LISTEN_NONE */
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (len == -1 && errno != EINTR) {
|
||||||
|
log_error("reopening socket.");
|
||||||
|
change_listen_mode(listen_mode); /* just close and reopen */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (packet.xid != xid) {
|
||||||
|
log_line("Ignoring XID %lx (our xid is %lx).",
|
||||||
|
(uint32_t) packet.xid, xid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
|
||||||
|
log_line("couldnt get option from packet -- ignoring");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dhcp_state) {
|
||||||
|
case INIT_SELECTING:
|
||||||
|
init_selecting_packet(&packet, message);
|
||||||
break;
|
break;
|
||||||
case ARP_CHECK:
|
case ARP_CHECK:
|
||||||
/* No response to ARP obviously means that the address is free. */
|
/* We ignore dhcp packets for now. This state will
|
||||||
arp_success();
|
* be changed by the callback for arp ping.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
case RENEW_REQUESTED:
|
||||||
|
case REQUESTING:
|
||||||
|
case RENEWING:
|
||||||
|
case REBINDING:
|
||||||
|
dhcp_ack_or_nak_packet(&packet, message);
|
||||||
|
break;
|
||||||
|
case BOUND:
|
||||||
|
case RELEASED:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -457,113 +598,6 @@ static void handle_arp_response(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_packet(void)
|
|
||||||
{
|
|
||||||
unsigned char *temp = NULL, *message = NULL;
|
|
||||||
int len;
|
|
||||||
struct dhcpMessage packet;
|
|
||||||
|
|
||||||
if (listen_mode == LISTEN_KERNEL)
|
|
||||||
len = get_packet(&packet, listenFd);
|
|
||||||
else if (listen_mode == LISTEN_RAW)
|
|
||||||
len = get_raw_packet(&packet, listenFd);
|
|
||||||
else /* LISTEN_NONE */
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (len == -1 && errno != EINTR) {
|
|
||||||
log_error("reopening socket.");
|
|
||||||
change_listen_mode(listen_mode); /* just close and reopen */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (packet.xid != xid) {
|
|
||||||
log_line("Ignoring XID %lx (our xid is %lx).",
|
|
||||||
(uint32_t) packet.xid, xid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
|
|
||||||
log_line("couldnt get option from packet -- ignoring");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (dhcp_state) {
|
|
||||||
case INIT_SELECTING:
|
|
||||||
/* Must be a DHCPOFFER to one of our xid's */
|
|
||||||
if (*message == DHCPOFFER) {
|
|
||||||
if ((temp = get_option(&packet, DHCP_SERVER_ID))) {
|
|
||||||
/* Memcpy to a temp buffer to force alignment */
|
|
||||||
memcpy(&server_addr, temp, 4);
|
|
||||||
xid = packet.xid;
|
|
||||||
requested_ip = packet.yiaddr;
|
|
||||||
|
|
||||||
/* enter requesting state */
|
|
||||||
dhcp_state = REQUESTING;
|
|
||||||
timeout = 0;
|
|
||||||
packet_num = 0;
|
|
||||||
} else {
|
|
||||||
log_line("No server ID in message");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ARP_CHECK:
|
|
||||||
/* We ignore dhcp packets for now. This state will
|
|
||||||
* be changed by the callback for arp ping.
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
case RENEW_REQUESTED:
|
|
||||||
case REQUESTING:
|
|
||||||
case RENEWING:
|
|
||||||
case REBINDING:
|
|
||||||
if (*message == DHCPACK) {
|
|
||||||
if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) {
|
|
||||||
log_line("No lease time received, assuming 1h.");
|
|
||||||
lease = 60 * 60;
|
|
||||||
} else {
|
|
||||||
/* Memcpy to a temp buffer to force alignment */
|
|
||||||
memcpy(&lease, temp, 4);
|
|
||||||
lease = ntohl(lease);
|
|
||||||
/* Enforce upper and lower bounds on lease. */
|
|
||||||
lease &= 0x0fffffff;
|
|
||||||
if (lease < RETRY_DELAY)
|
|
||||||
lease = RETRY_DELAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
arp_prev_dhcp_state = dhcp_state;
|
|
||||||
dhcp_state = ARP_CHECK;
|
|
||||||
memcpy(&arp_dhcp_packet, &packet, sizeof packet);
|
|
||||||
arpFd = arpping(arp_dhcp_packet.yiaddr, NULL, 0,
|
|
||||||
client_config.arp, client_config.interface);
|
|
||||||
epoll_add(arpFd);
|
|
||||||
timeout = 2000;
|
|
||||||
memset(&arpreply, 0, sizeof arpreply);
|
|
||||||
arpreply_offset = 0;
|
|
||||||
// Can transition to BOUND or INIT_SELECTING.
|
|
||||||
|
|
||||||
} else if (*message == DHCPNAK) {
|
|
||||||
/* return to init state */
|
|
||||||
log_line("Received DHCP NAK.");
|
|
||||||
run_script(&packet, SCRIPT_NAK);
|
|
||||||
if (dhcp_state != REQUESTING)
|
|
||||||
run_script(NULL, SCRIPT_DECONFIG);
|
|
||||||
dhcp_state = INIT_SELECTING;
|
|
||||||
timeout = 0;
|
|
||||||
requested_ip = 0;
|
|
||||||
packet_num = 0;
|
|
||||||
change_listen_mode(LISTEN_RAW);
|
|
||||||
// XXX: this isn't rfc compliant: should be exp backoff
|
|
||||||
sleep(3); /* avoid excessive network traffic */
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BOUND:
|
|
||||||
case RELEASED:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_signals()
|
static void setup_signals()
|
||||||
{
|
{
|
||||||
sigset_t mask;
|
sigset_t mask;
|
||||||
|
Loading…
Reference in New Issue
Block a user