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)
|
cmake_minimum_required (VERSION 2.6)
|
||||||
|
|
||||||
set(NDHC_SRCS
|
set(NDHC_SRCS
|
||||||
|
sys.c
|
||||||
options.c
|
options.c
|
||||||
socket.c
|
socket.c
|
||||||
packet.c
|
packet.c
|
||||||
|
timeout.c
|
||||||
script.c
|
script.c
|
||||||
clientpacket.c
|
clientpacket.c
|
||||||
arpping.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.
|
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||||
*/
|
*/
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/if_ether.h>
|
#include <netinet/if_ether.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "arpping.h"
|
#include "arpping.h"
|
||||||
|
#include "clientpacket.h"
|
||||||
|
#include "sys.h"
|
||||||
|
#include "script.h"
|
||||||
#include "dhcpd.h"
|
#include "dhcpd.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "strl.h"
|
#include "strl.h"
|
||||||
#include "io.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. */
|
/* 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,
|
static int arpping(uint32_t test_nip, const uint8_t *safe_mac,
|
||||||
uint8_t *from_mac, const char *interface)
|
uint32_t from_ip, uint8_t *from_mac, const char *interface)
|
||||||
{
|
{
|
||||||
int arpfd;
|
int arpfd;
|
||||||
int opt = 1;
|
int opt = 1;
|
||||||
@ -64,3 +79,102 @@ int arpping(uint32_t test_nip, const uint8_t *safe_mac, uint32_t from_ip,
|
|||||||
}
|
}
|
||||||
return arpfd;
|
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 <stdint.h>
|
||||||
#include <net/if_arp.h>
|
#include <net/if_arp.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "packet.h"
|
||||||
|
|
||||||
struct arpMsg {
|
struct arpMsg {
|
||||||
/* Ethernet header */
|
/* Ethernet header */
|
||||||
uint8_t h_dest[6]; /* 00 destination ether addr */
|
uint8_t h_dest[6]; /* 00 destination ether addr */
|
||||||
@ -27,7 +30,8 @@ enum {
|
|||||||
ARP_MSG_SIZE = 0x2a
|
ARP_MSG_SIZE = 0x2a
|
||||||
};
|
};
|
||||||
|
|
||||||
int arpping(uint32_t test_nip, const uint8_t *safe_mac, uint32_t from_ip,
|
void arp_check(struct client_state_t *cs, struct dhcpMessage *packet);
|
||||||
uint8_t *from_mac, const char *interface);
|
void arp_success(struct client_state_t *cs);
|
||||||
|
void handle_arp_response(struct client_state_t *cs);
|
||||||
|
|
||||||
#endif /* ARPPING_H_ */
|
#endif /* ARPPING_H_ */
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef DHCPC_H_
|
#ifndef DHCPC_H_
|
||||||
#define DHCPC_H_
|
#define DHCPC_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define NUMPACKETS 3 /* number of packets to send before delay */
|
#define NUMPACKETS 3 /* number of packets to send before delay */
|
||||||
#define RETRY_DELAY 30 /* time in seconds to delay after sending NUMPACKETS */
|
#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 "options.h"
|
||||||
#include "clientpacket.h"
|
#include "clientpacket.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
|
#include "timeout.h"
|
||||||
|
#include "sys.h"
|
||||||
#include "script.h"
|
#include "script.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
#include "arpping.h"
|
#include "arpping.h"
|
||||||
@ -95,35 +97,6 @@ struct client_config_t client_config = {
|
|||||||
|
|
||||||
static char pidfile[MAX_PATH_LENGTH] = PID_FILE_DEFAULT;
|
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)
|
static void show_usage(void)
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
@ -154,18 +127,18 @@ void change_listen_mode(int new_mode)
|
|||||||
new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
|
new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
|
||||||
cs.listenMode = new_mode;
|
cs.listenMode = new_mode;
|
||||||
if (cs.listenFd >= 0) {
|
if (cs.listenFd >= 0) {
|
||||||
epoll_del(cs.listenFd);
|
epoll_del(&cs, cs.listenFd);
|
||||||
close(cs.listenFd);
|
close(cs.listenFd);
|
||||||
cs.listenFd = -1;
|
cs.listenFd = -1;
|
||||||
}
|
}
|
||||||
if (new_mode == LM_KERNEL) {
|
if (new_mode == LM_KERNEL) {
|
||||||
cs.listenFd = listen_socket(INADDR_ANY, CLIENT_PORT,
|
cs.listenFd = listen_socket(INADDR_ANY, CLIENT_PORT,
|
||||||
client_config.interface);
|
client_config.interface);
|
||||||
epoll_add(cs.listenFd);
|
epoll_add(&cs, cs.listenFd);
|
||||||
}
|
}
|
||||||
else if (new_mode == LM_RAW) {
|
else if (new_mode == LM_RAW) {
|
||||||
cs.listenFd = raw_socket(client_config.ifindex);
|
cs.listenFd = raw_socket(client_config.ifindex);
|
||||||
epoll_add(cs.listenFd);
|
epoll_add(&cs, cs.listenFd);
|
||||||
}
|
}
|
||||||
else /* LM_NONE */
|
else /* LM_NONE */
|
||||||
return;
|
return;
|
||||||
@ -185,7 +158,7 @@ static void perform_renew(void)
|
|||||||
change_listen_mode(LM_KERNEL);
|
change_listen_mode(LM_KERNEL);
|
||||||
case DS_ARP_CHECK:
|
case DS_ARP_CHECK:
|
||||||
// Cancel arp ping in progress and treat as previous state.
|
// Cancel arp ping in progress and treat as previous state.
|
||||||
epoll_del(cs.arpFd);
|
epoll_del(&cs, cs.arpFd);
|
||||||
cs.arpFd = -1;
|
cs.arpFd = -1;
|
||||||
cs.dhcpState = cs.arpPrevState;
|
cs.dhcpState = cs.arpPrevState;
|
||||||
goto retry;
|
goto retry;
|
||||||
@ -231,7 +204,7 @@ static void perform_release(void)
|
|||||||
log_line("Entering released state.");
|
log_line("Entering released state.");
|
||||||
|
|
||||||
if (cs.dhcpState == DS_ARP_CHECK) {
|
if (cs.dhcpState == DS_ARP_CHECK) {
|
||||||
epoll_del(cs.arpFd);
|
epoll_del(&cs, cs.arpFd);
|
||||||
cs.arpFd = -1;
|
cs.arpFd = -1;
|
||||||
}
|
}
|
||||||
change_listen_mode(LM_NONE);
|
change_listen_mode(LM_NONE);
|
||||||
@ -239,7 +212,7 @@ static void perform_release(void)
|
|||||||
cs.timeout = -1;
|
cs.timeout = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void background(void)
|
void background(void)
|
||||||
{
|
{
|
||||||
static char called;
|
static char called;
|
||||||
if (!called && daemon(0, 0) == -1) {
|
if (!called && daemon(0, 0) == -1) {
|
||||||
@ -254,226 +227,6 @@ static void background(void)
|
|||||||
write_pid(pidfile);
|
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()
|
static void setup_signals()
|
||||||
{
|
{
|
||||||
sigset_t mask;
|
sigset_t mask;
|
||||||
@ -527,9 +280,9 @@ static void do_work(void)
|
|||||||
cs.epollFd = epoll_create1(0);
|
cs.epollFd = epoll_create1(0);
|
||||||
if (cs.epollFd == -1)
|
if (cs.epollFd == -1)
|
||||||
suicide("epoll_create1 failed");
|
suicide("epoll_create1 failed");
|
||||||
epoll_add(cs.signalFd);
|
epoll_add(&cs, cs.signalFd);
|
||||||
change_listen_mode(LM_RAW);
|
change_listen_mode(LM_RAW);
|
||||||
handle_timeout();
|
handle_timeout(&cs);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
last_awake = curms();
|
last_awake = curms();
|
||||||
@ -547,7 +300,7 @@ static void do_work(void)
|
|||||||
else if (fd == cs.listenFd)
|
else if (fd == cs.listenFd)
|
||||||
handle_packet(&cs);
|
handle_packet(&cs);
|
||||||
else if (fd == cs.arpFd)
|
else if (fd == cs.arpFd)
|
||||||
handle_arp_response();
|
handle_arp_response(&cs);
|
||||||
else
|
else
|
||||||
suicide("epoll_wait: unknown fd");
|
suicide("epoll_wait: unknown fd");
|
||||||
}
|
}
|
||||||
@ -556,7 +309,7 @@ static void do_work(void)
|
|||||||
cs.timeout -= timeout_delta;
|
cs.timeout -= timeout_delta;
|
||||||
if (cs.timeout <= 0) {
|
if (cs.timeout <= 0) {
|
||||||
cs.timeout = 0;
|
cs.timeout = 0;
|
||||||
handle_timeout();
|
handle_timeout(&cs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef SCRIPT_H_
|
#ifndef SCRIPT_H_
|
||||||
#define SCRIPT_H_
|
#define SCRIPT_H_
|
||||||
|
|
||||||
|
#include "packet.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SCRIPT_DECONFIG = 0,
|
SCRIPT_DECONFIG = 0,
|
||||||
SCRIPT_BOUND = 1,
|
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