Move dhcp state handling code out of netlink.c and into state.c. netlink.c

now just calls hooks exposed by state.c, just like the dhcp packet,
poll timeout, and signal code.

Make ifchange_deconfig() idempotent.
This commit is contained in:
Nicholas J. Kain 2011-07-04 22:10:14 -04:00
parent 88804e0102
commit 4453391154
4 changed files with 79 additions and 77 deletions

View File

@ -1,5 +1,5 @@
/* ifchange.c - functions to call the interface change daemon /* ifchange.c - functions to call the interface change daemon
* Time-stamp: <2011-07-04 21:35:02 njk> * Time-stamp: <2011-07-04 22:03:35 njk>
* *
* (c) 2004-2011 Nicholas J. Kain <njkain at gmail dot com> * (c) 2004-2011 Nicholas J. Kain <njkain at gmail dot com>
* *
@ -39,7 +39,8 @@
#include "io.h" #include "io.h"
#include "ifchange.h" #include "ifchange.h"
static struct dhcpmsg cfg_packet; static int cfg_deconfig; // Set if the interface has already been deconfigured.
static struct dhcpmsg cfg_packet; // Copy of the current configuration packet.
// Fill buf with the ifchd command text of option 'option'. // Fill buf with the ifchd command text of option 'option'.
// Returns 0 if successful, -1 if nothing was filled in. // Returns 0 if successful, -1 if nothing was filled in.
@ -162,6 +163,9 @@ void ifchange_deconfig(void)
int sockfd; int sockfd;
char buf[256]; char buf[256];
if (cfg_deconfig)
return;
sockfd = open_ifch(); sockfd = open_ifch();
snprintf(buf, sizeof buf, "interface:%s:", client_config.interface); snprintf(buf, sizeof buf, "interface:%s:", client_config.interface);
@ -170,6 +174,7 @@ void ifchange_deconfig(void)
snprintf(buf, sizeof buf, "ip:0.0.0.0:"); snprintf(buf, sizeof buf, "ip:0.0.0.0:");
sockwrite(sockfd, buf, strlen(buf)); sockwrite(sockfd, buf, strlen(buf));
cfg_deconfig = 1;
memset(&cfg_packet, 0, sizeof cfg_packet); memset(&cfg_packet, 0, sizeof cfg_packet);
close(sockfd); close(sockfd);
@ -223,6 +228,7 @@ void ifchange_bind(struct dhcpmsg *packet)
send_cmd(sockfd, packet, DHCP_BROADCAST); send_cmd(sockfd, packet, DHCP_BROADCAST);
send_cmd(sockfd, packet, DHCP_WINS_SERVER); send_cmd(sockfd, packet, DHCP_WINS_SERVER);
cfg_deconfig = 0;
memcpy(&cfg_packet, packet, sizeof cfg_packet); memcpy(&cfg_packet, packet, sizeof cfg_packet);
close(sockfd); close(sockfd);

View File

@ -21,48 +21,21 @@
#include <assert.h> #include <assert.h>
#include <asm/types.h> #include <asm/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h>
#include <net/if.h> #include <net/if.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <strings.h>
#include <string.h> #include <string.h>
#include <sys/select.h>
#include <fcntl.h>
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#include <poll.h> #include <poll.h>
#include "netlink.h" #include "netlink.h"
#include "ifchange.h"
#include "arp.h"
#include "log.h" #include "log.h"
#include "nl.h" #include "nl.h"
#include "state.h"
static char nlbuf[8192]; static char nlbuf[8192];
int nlportid; int nlportid;
static void restart_if(struct client_state_t *cs)
{
log_line("nl: %s back, querying for new lease", client_config.interface);
// XXX: Same as packet.c - merge somehow?
ifchange_deconfig();
cs->dhcpState = DS_SELECTING;
cs->timeout = 0;
cs->clientAddr = 0;
cs->packetNum = 0;
set_listen_raw(cs);
}
static void sleep_if(struct client_state_t *cs)
{
arp_close_fd(cs);
set_listen_none(cs);
cs->dhcpState = DS_RELEASED;
cs->timeout = -1;
}
static int nlrtattr_assign(struct nlattr *attr, int type, void *data) static int nlrtattr_assign(struct nlattr *attr, int type, void *data)
{ {
struct nlattr **tb = data; struct nlattr **tb = data;
@ -114,33 +87,17 @@ static int nl_process_msgs(const struct nlmsghdr *nlh, void *data)
if (ifm->ifi_flags & IFF_RUNNING) { if (ifm->ifi_flags & IFF_RUNNING) {
if (cs->ifsPrevState != IFS_UP) { if (cs->ifsPrevState != IFS_UP) {
cs->ifsPrevState = IFS_UP; cs->ifsPrevState = IFS_UP;
// If we have a lease, then check to see ifup_action(cs);
// if our gateway is still valid (via ARP).
// If it fails, state -> SELECTING.
if (cs->dhcpState == DS_BOUND) {
if (arp_gw_check(cs) == -1)
log_warning("nl: arp_gw_check could not make arp socket, assuming lease is still OK");
else
log_line("nl: interface back, revalidating lease");
// If we don't have a lease, state -> SELECTING.
} else if (cs->dhcpState != DS_SELECTING)
restart_if(cs);
} }
} else { } else if (cs->ifsPrevState != IFS_DOWN) {
// No hardware carrier. // Interface configured, but no hardware carrier.
if (cs->ifsPrevState != IFS_DOWN) {
log_line("Interface carrier down. Going to sleep.");
cs->ifsPrevState = IFS_DOWN; cs->ifsPrevState = IFS_DOWN;
sleep_if(cs); ifnocarrier_action(cs);
} }
} } else if (cs->ifsPrevState != IFS_SHUT) {
} else {
// User shut down the interface. // User shut down the interface.
if (cs->ifsPrevState != IFS_SHUT) {
log_line("Interface shut down. Going to sleep.");
cs->ifsPrevState = IFS_SHUT; cs->ifsPrevState = IFS_SHUT;
sleep_if(cs); ifdown_action(cs);
}
} }
break; break;
case RTM_DELLINK: case RTM_DELLINK:

View File

@ -56,6 +56,17 @@ static int delay_timeout(int numpackets)
return to * 1000; return to * 1000;
} }
static void reinit_selecting(struct client_state_t *cs, int timeout)
{
ifchange_deconfig();
cs->dhcpState = DS_SELECTING;
cs->timeout = timeout;
cs->clientAddr = 0;
cs->packetNum = 0;
set_listen_raw(cs);
}
// Triggered after a DHCP lease request packet has been sent and no reply has // 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 // been received within the response wait time. If we've not exceeded the
// maximum number of request retransmits, then send another packet and wait // maximum number of request retransmits, then send another packet and wait
@ -66,12 +77,8 @@ static void requesting_timeout(struct client_state_t *cs)
send_selecting(cs); send_selecting(cs);
cs->timeout = delay_timeout(cs->packetNum); cs->timeout = delay_timeout(cs->packetNum);
cs->packetNum++; cs->packetNum++;
} else { } else
cs->dhcpState = DS_SELECTING; reinit_selecting(cs, 0);
cs->timeout = 0;
cs->packetNum = 0;
set_listen_raw(cs);
}
} }
// Triggered when the lease has been held for a significant fraction of its // Triggered when the lease has been held for a significant fraction of its
@ -86,12 +93,8 @@ static void bound_timeout(struct client_state_t *cs)
static void lease_timedout(struct client_state_t *cs) static void lease_timedout(struct client_state_t *cs)
{ {
cs->dhcpState = DS_SELECTING;
log_line("Lease lost, entering init state."); log_line("Lease lost, entering init state.");
ifchange_deconfig(); reinit_selecting(cs, 0);
cs->timeout = 0;
cs->packetNum = 0;
set_listen_raw(cs);
} }
// Triggered when a DHCP renew request has been sent and no reply has been // Triggered when a DHCP renew request has been sent and no reply has been
@ -173,22 +176,12 @@ static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet,
// Can transition from DS_ARP_CHECK to DS_BOUND or DS_SELECTING. // Can transition from DS_ARP_CHECK to DS_BOUND or DS_SELECTING.
if (arp_check(cs, packet) == -1) { if (arp_check(cs, packet) == -1) {
log_warning("arp_check failed to make arp socket, retrying lease"); log_warning("arp_check failed to make arp socket, retrying lease");
ifchange_deconfig(); reinit_selecting(cs, 3000);
cs->dhcpState = DS_SELECTING;
cs->timeout = 30000;
cs->clientAddr = 0;
cs->packetNum = 0;
set_listen_raw(cs);
} }
} else if (*message == DHCPNAK) { } else if (*message == DHCPNAK) {
log_line("Received DHCP NAK."); log_line("Received DHCP NAK.");
ifchange_deconfig(); reinit_selecting(cs, 3000);
cs->dhcpState = DS_SELECTING;
cs->timeout = 3000;
cs->clientAddr = 0;
cs->packetNum = 0;
set_listen_raw(cs);
} }
} }
@ -289,6 +282,47 @@ static void frenew(struct client_state_t *cs)
cs->timeout = 0; cs->timeout = 0;
} }
static void restart_if(struct client_state_t *cs)
{
log_line("nl: %s back, querying for new lease", client_config.interface);
reinit_selecting(cs, 0);
}
static void sleep_if(struct client_state_t *cs)
{
arp_close_fd(cs);
set_listen_none(cs);
cs->dhcpState = DS_RELEASED;
cs->timeout = -1;
}
void ifup_action(struct client_state_t *cs)
{
// If we have a lease, then check to see
// if our gateway is still valid (via ARP).
// If it fails, state -> SELECTING.
if (cs->dhcpState == DS_BOUND) {
if (arp_gw_check(cs) == -1)
log_warning("nl: arp_gw_check could not make arp socket, assuming lease is still OK");
else
log_line("nl: interface back, revalidating lease");
// If we don't have a lease, state -> SELECTING.
} else if (cs->dhcpState != DS_SELECTING)
restart_if(cs);
}
void ifdown_action(struct client_state_t *cs)
{
log_line("Interface shut down. Going to sleep.");
sleep_if(cs);
}
void ifnocarrier_action(struct client_state_t *cs)
{
log_line("Interface carrier down. Going to sleep.");
sleep_if(cs);
}
void packet_action(struct client_state_t *cs, struct dhcpmsg *packet, void packet_action(struct client_state_t *cs, struct dhcpmsg *packet,
uint8_t *message) uint8_t *message)
{ {

View File

@ -21,5 +21,10 @@ void packet_action(struct client_state_t *cs, struct dhcpmsg *packet,
void timeout_action(struct client_state_t *cs); void timeout_action(struct client_state_t *cs);
void force_renew_action(struct client_state_t *cs); void force_renew_action(struct client_state_t *cs);
void force_release_action(struct client_state_t *cs); void force_release_action(struct client_state_t *cs);
void ifup_action(struct client_state_t *cs);
void ifnocarrier_action(struct client_state_t *cs);
void ifdown_action(struct client_state_t *cs);
#endif #endif