Move timeout and arp handling code out to arpping.c and timeout.c.
This commit is contained in:
parent
adcc4bdd3d
commit
94ad810260
@ -3,9 +3,11 @@ project (ndhc)
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
|
||||
set(NDHC_SRCS
|
||||
sys.c
|
||||
options.c
|
||||
socket.c
|
||||
packet.c
|
||||
timeout.c
|
||||
script.c
|
||||
clientpacket.c
|
||||
arpping.c
|
||||
|
118
ndhc/arpping.c
118
ndhc/arpping.c
@ -5,21 +5,36 @@
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#include "arpping.h"
|
||||
#include "clientpacket.h"
|
||||
#include "sys.h"
|
||||
#include "script.h"
|
||||
#include "dhcpd.h"
|
||||
#include "log.h"
|
||||
#include "strl.h"
|
||||
#include "io.h"
|
||||
|
||||
static struct arpMsg arpreply;
|
||||
static int arpreply_offset;
|
||||
static struct dhcpMessage arp_dhcp_packet;
|
||||
|
||||
// from ndhc.c
|
||||
void change_listen_mode(int new_mode);
|
||||
void background(void);
|
||||
|
||||
/* Returns fd of the arp socket, or -1 on failure. */
|
||||
int arpping(uint32_t test_nip, const uint8_t *safe_mac, uint32_t from_ip,
|
||||
uint8_t *from_mac, const char *interface)
|
||||
static int arpping(uint32_t test_nip, const uint8_t *safe_mac,
|
||||
uint32_t from_ip, uint8_t *from_mac, const char *interface)
|
||||
{
|
||||
int arpfd;
|
||||
int opt = 1;
|
||||
@ -64,3 +79,102 @@ int arpping(uint32_t test_nip, const uint8_t *safe_mac, uint32_t from_ip,
|
||||
}
|
||||
return arpfd;
|
||||
}
|
||||
|
||||
// only called from packet.c
|
||||
void arp_check(struct client_state_t *cs, struct dhcpMessage *packet)
|
||||
{
|
||||
cs->arpPrevState = cs->dhcpState;
|
||||
cs->dhcpState = DS_ARP_CHECK;
|
||||
memcpy(&arp_dhcp_packet, packet, sizeof (struct dhcpMessage));
|
||||
cs->arpFd = arpping(arp_dhcp_packet.yiaddr, NULL, 0,
|
||||
client_config.arp, client_config.interface);
|
||||
epoll_add(cs, cs->arpFd);
|
||||
cs->timeout = 2000;
|
||||
memset(&arpreply, 0, sizeof arpreply);
|
||||
arpreply_offset = 0;
|
||||
}
|
||||
|
||||
static void arp_failed(struct client_state_t *cs)
|
||||
{
|
||||
log_line("Offered address is in use: declining.");
|
||||
epoll_del(cs, cs->arpFd);
|
||||
cs->arpFd = -1;
|
||||
send_decline(cs->xid, cs->serverAddr, arp_dhcp_packet.yiaddr);
|
||||
|
||||
if (cs->arpPrevState != DS_REQUESTING)
|
||||
run_script(NULL, SCRIPT_DECONFIG);
|
||||
cs->dhcpState = DS_INIT_SELECTING;
|
||||
cs->requestedIP = 0;
|
||||
cs->timeout = 0;
|
||||
cs->packetNum = 0;
|
||||
change_listen_mode(LM_RAW);
|
||||
}
|
||||
|
||||
// only called from timeout.c
|
||||
void arp_success(struct client_state_t *cs)
|
||||
{
|
||||
struct in_addr temp_addr;
|
||||
|
||||
epoll_del(cs, cs->arpFd);
|
||||
cs->arpFd = -1;
|
||||
|
||||
/* enter bound state */
|
||||
cs->t1 = cs->lease >> 1;
|
||||
/* little fixed point for n * .875 */
|
||||
cs->t2 = (cs->lease * 0x7) >> 3;
|
||||
cs->timeout = cs->t1 * 1000;
|
||||
cs->leaseStartTime = curms();
|
||||
|
||||
temp_addr.s_addr = arp_dhcp_packet.yiaddr;
|
||||
log_line("Lease of %s obtained, lease time %ld.",
|
||||
inet_ntoa(temp_addr), cs->lease);
|
||||
cs->requestedIP = arp_dhcp_packet.yiaddr;
|
||||
run_script(&arp_dhcp_packet,
|
||||
((cs->arpPrevState == DS_RENEWING ||
|
||||
cs->arpPrevState == DS_REBINDING)
|
||||
? SCRIPT_RENEW : SCRIPT_BOUND));
|
||||
|
||||
cs->dhcpState = DS_BOUND;
|
||||
change_listen_mode(LM_NONE);
|
||||
if (client_config.quit_after_lease)
|
||||
exit(EXIT_SUCCESS);
|
||||
if (!client_config.foreground)
|
||||
background();
|
||||
}
|
||||
|
||||
typedef uint32_t aliased_uint32_t __attribute__((__may_alias__));
|
||||
void handle_arp_response(struct client_state_t *cs)
|
||||
{
|
||||
if (arpreply_offset < sizeof arpreply) {
|
||||
int r = safe_read(cs->arpFd, (char *)&arpreply + arpreply_offset,
|
||||
sizeof arpreply - arpreply_offset);
|
||||
if (r < 0) {
|
||||
arp_failed(cs);
|
||||
return;
|
||||
} else
|
||||
arpreply_offset += r;
|
||||
}
|
||||
|
||||
//log3("sHaddr %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
//arp.sHaddr[0], arp.sHaddr[1], arp.sHaddr[2],
|
||||
//arp.sHaddr[3], arp.sHaddr[4], arp.sHaddr[5]);
|
||||
|
||||
if (arpreply_offset >= ARP_MSG_SIZE) {
|
||||
if (arpreply.operation == htons(ARPOP_REPLY)
|
||||
/* don't check: Linux returns invalid tHaddr (fixed in 2.6.24?) */
|
||||
/* && memcmp(arpreply.tHaddr, from_mac, 6) == 0 */
|
||||
&& *(aliased_uint32_t*)arpreply.sInaddr == arp_dhcp_packet.yiaddr)
|
||||
{
|
||||
/* if ARP source MAC matches safe_mac
|
||||
* (which is client's MAC), then it's not a conflict
|
||||
* (client simply already has this IP and replies to ARPs!)
|
||||
*/
|
||||
/* if (memcmp(safe_mac, arpreply.sHaddr, 6) == 0) */
|
||||
/* arp_success(); */
|
||||
arp_failed(cs);
|
||||
} else {
|
||||
memset(&arpreply, 0, sizeof arpreply);
|
||||
arpreply_offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,9 @@
|
||||
#include <stdint.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "packet.h"
|
||||
|
||||
struct arpMsg {
|
||||
/* Ethernet header */
|
||||
uint8_t h_dest[6]; /* 00 destination ether addr */
|
||||
@ -27,7 +30,8 @@ enum {
|
||||
ARP_MSG_SIZE = 0x2a
|
||||
};
|
||||
|
||||
int arpping(uint32_t test_nip, const uint8_t *safe_mac, uint32_t from_ip,
|
||||
uint8_t *from_mac, const char *interface);
|
||||
void arp_check(struct client_state_t *cs, struct dhcpMessage *packet);
|
||||
void arp_success(struct client_state_t *cs);
|
||||
void handle_arp_response(struct client_state_t *cs);
|
||||
|
||||
#endif /* ARPPING_H_ */
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef DHCPC_H_
|
||||
#define DHCPC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define NUMPACKETS 3 /* number of packets to send before delay */
|
||||
#define RETRY_DELAY 30 /* time in seconds to delay after sending NUMPACKETS */
|
||||
|
||||
|
271
ndhc/ndhc.c
271
ndhc/ndhc.c
@ -47,6 +47,8 @@
|
||||
#include "options.h"
|
||||
#include "clientpacket.h"
|
||||
#include "packet.h"
|
||||
#include "timeout.h"
|
||||
#include "sys.h"
|
||||
#include "script.h"
|
||||
#include "socket.h"
|
||||
#include "arpping.h"
|
||||
@ -95,35 +97,6 @@ struct client_config_t client_config = {
|
||||
|
||||
static char pidfile[MAX_PATH_LENGTH] = PID_FILE_DEFAULT;
|
||||
|
||||
static unsigned long long curms()
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL;
|
||||
}
|
||||
|
||||
static void epoll_add(int fd)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
int r;
|
||||
ev.events = EPOLLIN | EPOLLRDHUP | EPOLLERR | EPOLLHUP;
|
||||
ev.data.fd = fd;
|
||||
r = epoll_ctl(cs.epollFd, EPOLL_CTL_ADD, fd, &ev);
|
||||
if (r == -1)
|
||||
suicide("epoll_add failed %s", strerror(errno));
|
||||
}
|
||||
|
||||
static void epoll_del(int fd)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
int r;
|
||||
ev.events = EPOLLIN | EPOLLRDHUP | EPOLLERR | EPOLLHUP;
|
||||
ev.data.fd = fd;
|
||||
r = epoll_ctl(cs.epollFd, EPOLL_CTL_DEL, fd, &ev);
|
||||
if (r == -1)
|
||||
suicide("epoll_del failed %s", strerror(errno));
|
||||
}
|
||||
|
||||
static void show_usage(void)
|
||||
{
|
||||
printf(
|
||||
@ -154,18 +127,18 @@ void change_listen_mode(int new_mode)
|
||||
new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
|
||||
cs.listenMode = new_mode;
|
||||
if (cs.listenFd >= 0) {
|
||||
epoll_del(cs.listenFd);
|
||||
epoll_del(&cs, cs.listenFd);
|
||||
close(cs.listenFd);
|
||||
cs.listenFd = -1;
|
||||
}
|
||||
if (new_mode == LM_KERNEL) {
|
||||
cs.listenFd = listen_socket(INADDR_ANY, CLIENT_PORT,
|
||||
client_config.interface);
|
||||
epoll_add(cs.listenFd);
|
||||
epoll_add(&cs, cs.listenFd);
|
||||
}
|
||||
else if (new_mode == LM_RAW) {
|
||||
cs.listenFd = raw_socket(client_config.ifindex);
|
||||
epoll_add(cs.listenFd);
|
||||
epoll_add(&cs, cs.listenFd);
|
||||
}
|
||||
else /* LM_NONE */
|
||||
return;
|
||||
@ -185,7 +158,7 @@ static void perform_renew(void)
|
||||
change_listen_mode(LM_KERNEL);
|
||||
case DS_ARP_CHECK:
|
||||
// Cancel arp ping in progress and treat as previous state.
|
||||
epoll_del(cs.arpFd);
|
||||
epoll_del(&cs, cs.arpFd);
|
||||
cs.arpFd = -1;
|
||||
cs.dhcpState = cs.arpPrevState;
|
||||
goto retry;
|
||||
@ -231,7 +204,7 @@ static void perform_release(void)
|
||||
log_line("Entering released state.");
|
||||
|
||||
if (cs.dhcpState == DS_ARP_CHECK) {
|
||||
epoll_del(cs.arpFd);
|
||||
epoll_del(&cs, cs.arpFd);
|
||||
cs.arpFd = -1;
|
||||
}
|
||||
change_listen_mode(LM_NONE);
|
||||
@ -239,7 +212,7 @@ static void perform_release(void)
|
||||
cs.timeout = -1;
|
||||
}
|
||||
|
||||
static void background(void)
|
||||
void background(void)
|
||||
{
|
||||
static char called;
|
||||
if (!called && daemon(0, 0) == -1) {
|
||||
@ -254,226 +227,6 @@ static void background(void)
|
||||
write_pid(pidfile);
|
||||
}
|
||||
|
||||
static struct arpMsg arpreply;
|
||||
static int arpreply_offset;
|
||||
static struct dhcpMessage arp_dhcp_packet;
|
||||
|
||||
void arp_check(struct dhcpMessage *packet)
|
||||
{
|
||||
cs.arpPrevState = cs.dhcpState;
|
||||
cs.dhcpState = DS_ARP_CHECK;
|
||||
memcpy(&arp_dhcp_packet, packet, sizeof (struct dhcpMessage));
|
||||
cs.arpFd = arpping(arp_dhcp_packet.yiaddr, NULL, 0,
|
||||
client_config.arp, client_config.interface);
|
||||
epoll_add(cs.arpFd);
|
||||
cs.timeout = 2000;
|
||||
memset(&arpreply, 0, sizeof arpreply);
|
||||
arpreply_offset = 0;
|
||||
}
|
||||
|
||||
static void arp_failed(void)
|
||||
{
|
||||
log_line("Offered address is in use: declining.");
|
||||
epoll_del(cs.arpFd);
|
||||
cs.arpFd = -1;
|
||||
send_decline(cs.xid, cs.serverAddr, arp_dhcp_packet.yiaddr);
|
||||
|
||||
if (cs.arpPrevState != DS_REQUESTING)
|
||||
run_script(NULL, SCRIPT_DECONFIG);
|
||||
cs.dhcpState = DS_INIT_SELECTING;
|
||||
cs.requestedIP = 0;
|
||||
cs.timeout = 0;
|
||||
cs.packetNum = 0;
|
||||
change_listen_mode(LM_RAW);
|
||||
}
|
||||
|
||||
static void arp_success(void)
|
||||
{
|
||||
struct in_addr temp_addr;
|
||||
|
||||
epoll_del(cs.arpFd);
|
||||
cs.arpFd = -1;
|
||||
|
||||
/* enter bound state */
|
||||
cs.t1 = cs.lease >> 1;
|
||||
/* little fixed point for n * .875 */
|
||||
cs.t2 = (cs.lease * 0x7) >> 3;
|
||||
cs.timeout = cs.t1 * 1000;
|
||||
cs.leaseStartTime = curms();
|
||||
|
||||
temp_addr.s_addr = arp_dhcp_packet.yiaddr;
|
||||
log_line("Lease of %s obtained, lease time %ld.",
|
||||
inet_ntoa(temp_addr), cs.lease);
|
||||
cs.requestedIP = arp_dhcp_packet.yiaddr;
|
||||
run_script(&arp_dhcp_packet,
|
||||
((cs.arpPrevState == DS_RENEWING ||
|
||||
cs.arpPrevState == DS_REBINDING)
|
||||
? SCRIPT_RENEW : SCRIPT_BOUND));
|
||||
|
||||
cs.dhcpState = DS_BOUND;
|
||||
change_listen_mode(LM_NONE);
|
||||
if (client_config.quit_after_lease)
|
||||
exit(EXIT_SUCCESS);
|
||||
if (!client_config.foreground)
|
||||
background();
|
||||
}
|
||||
|
||||
static void init_selecting_timeout()
|
||||
{
|
||||
if (cs.packetNum < NUMPACKETS) {
|
||||
if (cs.packetNum == 0)
|
||||
cs.xid = random_xid();
|
||||
/* broadcast */
|
||||
send_discover(cs.xid, cs.requestedIP);
|
||||
|
||||
cs.timeout = ((cs.packetNum == NUMPACKETS - 1) ? 4 : 2) * 1000;
|
||||
cs.packetNum++;
|
||||
} else {
|
||||
if (client_config.background_if_no_lease) {
|
||||
log_line("No lease, going to background.");
|
||||
background();
|
||||
} else if (client_config.abort_if_no_lease) {
|
||||
log_line("No lease, failing.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* wait to try again */
|
||||
cs.packetNum = 0;
|
||||
cs.timeout = RETRY_DELAY * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
static void renew_requested_timeout()
|
||||
{
|
||||
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 {
|
||||
/* timed out, go back to init state */
|
||||
run_script(NULL, SCRIPT_DECONFIG);
|
||||
cs.dhcpState = DS_INIT_SELECTING;
|
||||
cs.timeout = 0;
|
||||
cs.packetNum = 0;
|
||||
change_listen_mode(LM_RAW);
|
||||
}
|
||||
}
|
||||
|
||||
static void requesting_timeout()
|
||||
{
|
||||
if (cs.packetNum < NUMPACKETS) {
|
||||
/* send broadcast request packet */
|
||||
send_selecting(cs.xid, cs.serverAddr, cs.requestedIP);
|
||||
cs.timeout = ((cs.packetNum == NUMPACKETS - 1) ? 10 : 2) * 1000;
|
||||
cs.packetNum++;
|
||||
} else {
|
||||
/* timed out, go back to init state */
|
||||
cs.dhcpState = DS_INIT_SELECTING;
|
||||
cs.timeout = 0;
|
||||
cs.packetNum = 0;
|
||||
change_listen_mode(LM_RAW);
|
||||
}
|
||||
}
|
||||
|
||||
static void renewing_timeout()
|
||||
{
|
||||
/* Either set a new T1, or enter DS_REBINDING state */
|
||||
if ((cs.t2 - cs.t1) <= (cs.lease / 14400 + 1)) {
|
||||
/* timed out, enter rebinding state */
|
||||
cs.dhcpState = DS_REBINDING;
|
||||
cs.timeout = (cs.t2 - cs.t1) * 1000;
|
||||
log_line("Entering rebinding state.");
|
||||
} else {
|
||||
/* send a request packet */
|
||||
send_renew(cs.xid, cs.serverAddr, cs.requestedIP); /* unicast */
|
||||
|
||||
cs.t1 = ((cs.t2 - cs.t1) >> 1) + cs.t1;
|
||||
cs.timeout = (cs.t1 * 1000) - (curms() - cs.leaseStartTime);
|
||||
}
|
||||
}
|
||||
|
||||
static void bound_timeout()
|
||||
{
|
||||
/* Lease is starting to run out, time to enter renewing state */
|
||||
cs.dhcpState = DS_RENEWING;
|
||||
change_listen_mode(LM_KERNEL);
|
||||
log_line("Entering renew state.");
|
||||
renewing_timeout();
|
||||
}
|
||||
|
||||
static void rebinding_timeout()
|
||||
{
|
||||
/* 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.");
|
||||
run_script(NULL, SCRIPT_DECONFIG);
|
||||
cs.timeout = 0;
|
||||
cs.packetNum = 0;
|
||||
change_listen_mode(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 */
|
||||
static void handle_timeout(void)
|
||||
{
|
||||
switch (cs.dhcpState) {
|
||||
case DS_INIT_SELECTING: init_selecting_timeout(); break;
|
||||
case DS_RENEW_REQUESTED: renew_requested_timeout(); break;
|
||||
case DS_REQUESTING: requesting_timeout(); break;
|
||||
case DS_RENEWING: renewing_timeout(); break;
|
||||
case DS_BOUND: bound_timeout(); break;
|
||||
case DS_REBINDING: rebinding_timeout(); break;
|
||||
case DS_RELEASED: cs.timeout = -1; break;
|
||||
case DS_ARP_CHECK: arp_success(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
typedef uint32_t aliased_uint32_t __attribute__((__may_alias__));
|
||||
static void handle_arp_response(void)
|
||||
{
|
||||
if (arpreply_offset < sizeof arpreply) {
|
||||
int r = safe_read(cs.arpFd, (char *)&arpreply + arpreply_offset,
|
||||
sizeof arpreply - arpreply_offset);
|
||||
if (r < 0) {
|
||||
arp_failed();
|
||||
return;
|
||||
} else
|
||||
arpreply_offset += r;
|
||||
}
|
||||
|
||||
//log3("sHaddr %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
//arp.sHaddr[0], arp.sHaddr[1], arp.sHaddr[2],
|
||||
//arp.sHaddr[3], arp.sHaddr[4], arp.sHaddr[5]);
|
||||
|
||||
if (arpreply_offset >= ARP_MSG_SIZE) {
|
||||
if (arpreply.operation == htons(ARPOP_REPLY)
|
||||
/* don't check: Linux returns invalid tHaddr (fixed in 2.6.24?) */
|
||||
/* && memcmp(arpreply.tHaddr, from_mac, 6) == 0 */
|
||||
&& *(aliased_uint32_t*)arpreply.sInaddr == arp_dhcp_packet.yiaddr)
|
||||
{
|
||||
/* if ARP source MAC matches safe_mac
|
||||
* (which is client's MAC), then it's not a conflict
|
||||
* (client simply already has this IP and replies to ARPs!)
|
||||
*/
|
||||
/* if (memcmp(safe_mac, arpreply.sHaddr, 6) == 0) */
|
||||
/* arp_success(); */
|
||||
arp_failed();
|
||||
} else {
|
||||
memset(&arpreply, 0, sizeof arpreply);
|
||||
arpreply_offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_signals()
|
||||
{
|
||||
sigset_t mask;
|
||||
@ -527,9 +280,9 @@ static void do_work(void)
|
||||
cs.epollFd = epoll_create1(0);
|
||||
if (cs.epollFd == -1)
|
||||
suicide("epoll_create1 failed");
|
||||
epoll_add(cs.signalFd);
|
||||
epoll_add(&cs, cs.signalFd);
|
||||
change_listen_mode(LM_RAW);
|
||||
handle_timeout();
|
||||
handle_timeout(&cs);
|
||||
|
||||
for (;;) {
|
||||
last_awake = curms();
|
||||
@ -547,7 +300,7 @@ static void do_work(void)
|
||||
else if (fd == cs.listenFd)
|
||||
handle_packet(&cs);
|
||||
else if (fd == cs.arpFd)
|
||||
handle_arp_response();
|
||||
handle_arp_response(&cs);
|
||||
else
|
||||
suicide("epoll_wait: unknown fd");
|
||||
}
|
||||
@ -556,7 +309,7 @@ static void do_work(void)
|
||||
cs.timeout -= timeout_delta;
|
||||
if (cs.timeout <= 0) {
|
||||
cs.timeout = 0;
|
||||
handle_timeout();
|
||||
handle_timeout(&cs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef SCRIPT_H_
|
||||
#define SCRIPT_H_
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
enum {
|
||||
SCRIPT_DECONFIG = 0,
|
||||
SCRIPT_BOUND = 1,
|
||||
|
132
ndhc/timeout.c
Normal file
132
ndhc/timeout.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "timeout.h"
|
||||
#include "config.h"
|
||||
#include "script.h"
|
||||
#include "clientpacket.h"
|
||||
#include "arpping.h"
|
||||
#include "log.h"
|
||||
|
||||
// from ndhc.c
|
||||
void change_listen_mode(int new_mode);
|
||||
void background(void);
|
||||
|
||||
static void init_selecting_timeout(struct client_state_t *cs)
|
||||
{
|
||||
if (cs->packetNum < NUMPACKETS) {
|
||||
if (cs->packetNum == 0)
|
||||
cs->xid = random_xid();
|
||||
/* broadcast */
|
||||
send_discover(cs->xid, cs->requestedIP);
|
||||
|
||||
cs->timeout = ((cs->packetNum == NUMPACKETS - 1) ? 4 : 2) * 1000;
|
||||
cs->packetNum++;
|
||||
} else {
|
||||
if (client_config.background_if_no_lease) {
|
||||
log_line("No lease, going to background.");
|
||||
background();
|
||||
} else if (client_config.abort_if_no_lease) {
|
||||
log_line("No lease, failing.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* wait to try again */
|
||||
cs->packetNum = 0;
|
||||
cs->timeout = RETRY_DELAY * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
/* timed out, go back to init state */
|
||||
run_script(NULL, SCRIPT_DECONFIG);
|
||||
cs->dhcpState = DS_INIT_SELECTING;
|
||||
cs->timeout = 0;
|
||||
cs->packetNum = 0;
|
||||
change_listen_mode(LM_RAW);
|
||||
}
|
||||
}
|
||||
|
||||
static void requesting_timeout(struct client_state_t *cs)
|
||||
{
|
||||
if (cs->packetNum < NUMPACKETS) {
|
||||
/* send broadcast request packet */
|
||||
send_selecting(cs->xid, cs->serverAddr, cs->requestedIP);
|
||||
cs->timeout = ((cs->packetNum == NUMPACKETS - 1) ? 10 : 2) * 1000;
|
||||
cs->packetNum++;
|
||||
} else {
|
||||
/* timed out, go back to init state */
|
||||
cs->dhcpState = DS_INIT_SELECTING;
|
||||
cs->timeout = 0;
|
||||
cs->packetNum = 0;
|
||||
change_listen_mode(LM_RAW);
|
||||
}
|
||||
}
|
||||
|
||||
static void renewing_timeout(struct client_state_t *cs)
|
||||
{
|
||||
/* Either set a new T1, or enter DS_REBINDING state */
|
||||
if ((cs->t2 - cs->t1) <= (cs->lease / 14400 + 1)) {
|
||||
/* timed out, enter rebinding state */
|
||||
cs->dhcpState = DS_REBINDING;
|
||||
cs->timeout = (cs->t2 - cs->t1) * 1000;
|
||||
log_line("Entering rebinding state.");
|
||||
} else {
|
||||
/* send a request packet */
|
||||
send_renew(cs->xid, cs->serverAddr, cs->requestedIP); /* unicast */
|
||||
|
||||
cs->t1 = ((cs->t2 - cs->t1) >> 1) + cs->t1;
|
||||
cs->timeout = (cs->t1 * 1000) - (curms() - cs->leaseStartTime);
|
||||
}
|
||||
}
|
||||
|
||||
static void bound_timeout(struct client_state_t *cs)
|
||||
{
|
||||
/* Lease is starting to run out, time to enter renewing state */
|
||||
cs->dhcpState = DS_RENEWING;
|
||||
change_listen_mode(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.");
|
||||
run_script(NULL, SCRIPT_DECONFIG);
|
||||
cs->timeout = 0;
|
||||
cs->packetNum = 0;
|
||||
change_listen_mode(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;
|
||||
default: break;
|
||||
}
|
||||
}
|
9
ndhc/timeout.h
Normal file
9
ndhc/timeout.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef TIMEOUT_H_
|
||||
#define TIMEOUT_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "sys.h"
|
||||
|
||||
void handle_timeout(struct client_state_t *cs);
|
||||
|
||||
#endif /* TIMEOUT_H_ */
|
Loading…
Reference in New Issue
Block a user