Hardware link status can 'bounce' erratically while link properties are
being updated, so perform status debouncing. While ifch is doing work, the netlink events are ignored. Once ifch has finished its work, netlink events are no longer ignored. Making this work requires ifch to communicate back to ndhc, but it is no problem since the necessary pipes are already in place for IPC.
This commit is contained in:
parent
d8e3dc61ea
commit
6fcc43d169
@ -485,7 +485,7 @@ void arp_success(struct client_state_t *cs)
|
||||
cs->init = 0;
|
||||
last_conflict_ts = 0;
|
||||
arp_wake_ts[AS_COLLISION_CHECK] = -1;
|
||||
ifchange_bind(&arp_dhcp_packet);
|
||||
ifchange_bind(cs, &arp_dhcp_packet);
|
||||
if (cs->arpPrevState == DS_RENEWING || cs->arpPrevState == DS_REBINDING) {
|
||||
arp_switch_state(cs, AS_DEFENSE);
|
||||
} else {
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include "ifchange.h"
|
||||
#include "ifch_proto.h"
|
||||
|
||||
static int cfg_deconfig; // Set if the interface has already been deconfigured.
|
||||
static struct dhcpmsg cfg_packet; // Copy of the current configuration packet.
|
||||
|
||||
static int ifchd_cmd_u8(char *buf, size_t buflen, char *optname,
|
||||
@ -155,8 +154,9 @@ static int ifchd_cmd(char *buf, size_t buflen, uint8_t *optdata,
|
||||
}
|
||||
#undef IFCHD_SW_CMD
|
||||
|
||||
static void pipewrite(const char *buf, size_t count)
|
||||
static void pipewrite(struct client_state_t *cs, const char *buf, size_t count)
|
||||
{
|
||||
cs->ifchWorking = 1;
|
||||
if (safe_write(pToIfchW, buf, count) == -1) {
|
||||
log_error("pipewrite: write failed: %s", strerror(errno));
|
||||
return;
|
||||
@ -164,18 +164,18 @@ static void pipewrite(const char *buf, size_t count)
|
||||
log_line("Sent to ifchd: %s", buf);
|
||||
}
|
||||
|
||||
void ifchange_deconfig(void)
|
||||
void ifchange_deconfig(struct client_state_t *cs)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
if (cfg_deconfig)
|
||||
if (cs->ifDeconfig)
|
||||
return;
|
||||
cs->ifDeconfig = 1;
|
||||
|
||||
snprintf(buf, sizeof buf, "ip4:0.0.0.0,255.255.255.255;");
|
||||
log_line("Resetting %s IP configuration.", client_config.interface);
|
||||
pipewrite(buf, strlen(buf));
|
||||
pipewrite(cs, buf, strlen(buf));
|
||||
|
||||
cfg_deconfig = 1;
|
||||
memset(&cfg_packet, 0, sizeof cfg_packet);
|
||||
}
|
||||
|
||||
@ -258,7 +258,7 @@ static size_t send_cmd(char *out, size_t olen, struct dhcpmsg *packet,
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
void ifchange_bind(struct dhcpmsg *packet)
|
||||
void ifchange_bind(struct client_state_t *cs, struct dhcpmsg *packet)
|
||||
{
|
||||
char buf[2048];
|
||||
int tbs = 0;
|
||||
@ -275,8 +275,8 @@ void ifchange_bind(struct dhcpmsg *packet)
|
||||
tbs |= send_cmd(buf, sizeof buf, packet, DCODE_MTU);
|
||||
tbs |= send_cmd(buf, sizeof buf, packet, DCODE_WINS);
|
||||
if (tbs)
|
||||
pipewrite(buf, strlen(buf));
|
||||
pipewrite(cs, buf, strlen(buf));
|
||||
|
||||
cfg_deconfig = 0;
|
||||
cs->ifDeconfig = 0;
|
||||
memcpy(&cfg_packet, packet, sizeof cfg_packet);
|
||||
}
|
||||
|
@ -29,7 +29,7 @@
|
||||
#ifndef IFCHANGE_H_
|
||||
#define IFCHANGE_H_
|
||||
|
||||
void ifchange_bind(struct dhcpmsg *packet);
|
||||
void ifchange_deconfig(void);
|
||||
void ifchange_bind(struct client_state_t *cs, struct dhcpmsg *packet);
|
||||
void ifchange_deconfig(struct client_state_t *cs);
|
||||
|
||||
#endif
|
||||
|
28
ndhc/ifchd.c
28
ndhc/ifchd.c
@ -303,6 +303,24 @@ static void signal_dispatch(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void inform_execute(int success)
|
||||
{
|
||||
int r;
|
||||
char c = success ? '+' : '-';
|
||||
retry:
|
||||
r = safe_write(pToNdhcW, &c, sizeof c);
|
||||
if (r == 0) {
|
||||
// Remote end hung up.
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (r < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
goto retry;
|
||||
log_line("%s: (%s) error writing to ifch -> ndhc pipe: %s",
|
||||
client_config.interface, __func__, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_client_pipe(void)
|
||||
{
|
||||
char buf[MAX_BUF];
|
||||
@ -315,14 +333,18 @@ static void process_client_pipe(void)
|
||||
} else if (r < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return;
|
||||
log_line("ifch: error reading from ndhc -> ifch pipe: %s", strerror(errno));
|
||||
log_line("%s: (%s) error reading from ndhc -> ifch pipe: %s",
|
||||
client_config.interface, __func__, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (execute_buffer(buf) == -1) {
|
||||
log_line("ifch: execute_buffer was passed invalid commands: '%s'", buf);
|
||||
log_line("%s: (%s) execute_buffer was passed invalid commands: '%s'",
|
||||
client_config.interface, __func__, buf);
|
||||
inform_execute(0);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else
|
||||
inform_execute(1);
|
||||
}
|
||||
|
||||
void do_ifch_work(void)
|
||||
|
31
ndhc/ndhc.c
31
ndhc/ndhc.c
@ -71,6 +71,8 @@
|
||||
#include "ifchd.h"
|
||||
|
||||
struct client_state_t cs = {
|
||||
.ifchWorking = 0,
|
||||
.ifDeconfig = 0,
|
||||
.init = 1,
|
||||
.epollFd = -1,
|
||||
.signalFd = -1,
|
||||
@ -213,9 +215,29 @@ static int get_clientid_mac_string(char *str, size_t slen)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void handle_ifch_message(void)
|
||||
{
|
||||
char c;
|
||||
int r = safe_read(pToNdhcR, &c, sizeof c);
|
||||
if (r == 0) {
|
||||
// Remote end hung up.
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (r < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return;
|
||||
log_line("%s: (%s) error reading from ifch -> ndhc pipe: %s",
|
||||
client_config.interface, __func__, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (c == '+')
|
||||
cs.ifchWorking = 0;
|
||||
}
|
||||
|
||||
#define NDHC_NUM_EP_FDS 4
|
||||
static void do_ndhc_work(void)
|
||||
{
|
||||
struct epoll_event events[3];
|
||||
struct epoll_event events[NDHC_NUM_EP_FDS];
|
||||
long long nowts;
|
||||
int timeout;
|
||||
|
||||
@ -229,12 +251,13 @@ static void do_ndhc_work(void)
|
||||
setup_signals_ndhc();
|
||||
|
||||
epoll_add(cs.epollFd, cs.nlFd);
|
||||
epoll_add(cs.epollFd, pToNdhcR);
|
||||
set_listen_raw(&cs);
|
||||
nowts = curms();
|
||||
goto jumpstart;
|
||||
|
||||
for (;;) {
|
||||
int r = epoll_wait(cs.epollFd, events, 3, timeout);
|
||||
int r = epoll_wait(cs.epollFd, events, NDHC_NUM_EP_FDS, timeout);
|
||||
if (r == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
@ -251,6 +274,8 @@ static void do_ndhc_work(void)
|
||||
handle_arp_response(&cs);
|
||||
else if (fd == cs.nlFd)
|
||||
handle_nl_message(&cs);
|
||||
else if (fd == pToNdhcR)
|
||||
handle_ifch_message();
|
||||
else
|
||||
suicide("epoll_wait: unknown fd");
|
||||
}
|
||||
@ -336,7 +361,7 @@ static void ndhc_main(void) {
|
||||
drop_root(ndhc_uid, ndhc_gid);
|
||||
|
||||
if (cs.ifsPrevState != IFS_UP)
|
||||
ifchange_deconfig();
|
||||
ifchange_deconfig(&cs);
|
||||
|
||||
do_ndhc_work();
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ struct client_state_t {
|
||||
int dhcpState;
|
||||
int arpPrevState;
|
||||
int ifsPrevState;
|
||||
int ifchWorking; // ifch is performing interface changes.
|
||||
int ifDeconfig; // Set if the interface has already been deconfigured.
|
||||
int listenMode;
|
||||
int epollFd, signalFd, listenFd, arpFd, nlFd;
|
||||
int nlPortId;
|
||||
|
@ -89,6 +89,8 @@ static void nl_process_msgs(const struct nlmsghdr *nlh, void *data)
|
||||
get_if_index_and_mac(nlh, ifm);
|
||||
if (ifm->ifi_index != client_config.ifindex)
|
||||
break;
|
||||
if (cs->ifchWorking)
|
||||
break;
|
||||
// IFF_UP corresponds to ifconfig down or ifconfig up.
|
||||
if (ifm->ifi_flags & IFF_UP) {
|
||||
// IFF_RUNNING is the hardware carrier.
|
||||
@ -111,6 +113,8 @@ static void nl_process_msgs(const struct nlmsghdr *nlh, void *data)
|
||||
case RTM_DELLINK:
|
||||
if (ifm->ifi_index != client_config.ifindex)
|
||||
break;
|
||||
if (cs->ifchWorking)
|
||||
break;
|
||||
if (cs->ifsPrevState != IFS_REMOVED) {
|
||||
cs->ifsPrevState = IFS_REMOVED;
|
||||
log_line("Interface removed. Exiting.");
|
||||
|
@ -88,7 +88,7 @@ static int delay_timeout(size_t numpackets)
|
||||
|
||||
static void reinit_shared_deconfig(struct client_state_t *cs)
|
||||
{
|
||||
ifchange_deconfig();
|
||||
ifchange_deconfig(cs);
|
||||
arp_close_fd(cs);
|
||||
cs->clientAddr = 0;
|
||||
num_dhcp_requests = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user