diff --git a/src/arp.c b/src/arp.c index 30aa73d..3d1623d 100644 --- a/src/arp.c +++ b/src/arp.c @@ -63,7 +63,7 @@ int arp_probe_max = 2000; // maximum delay until repeated probe (ms) #define DEFEND_INTERVAL 10000 // minimum interval between defensive ARPs static struct arp_data garp = { - .wake_ts = { -1, -1, -1, -1, -1, -1 }, + .wake_ts = { -1, -1, -1, -1, -1, -1, -1 }, .send_stats = {{0,0},{0,0},{0,0}}, .last_conflict_ts = 0, .gw_check_initpings = 0, @@ -555,14 +555,30 @@ int arp_collision_timeout(struct client_state_t cs[static 1], long long nowts) int arp_query_gateway(struct client_state_t cs[static 1]) { + if (cs->sent_gw_query) { + garp.wake_ts[AS_QUERY_GW_SEND] = -1; + return ARPR_OK; + } if (arp_get_gw_hwaddr(cs) < 0) { log_warning("%s: (%s) Failed to send request to get gateway and agent hardware addresses: %s", client_config.interface, __func__, strerror(errno)); + garp.wake_ts[AS_QUERY_GW_SEND] = curms() + ARP_RETRANS_DELAY; return ARPR_FAIL; } + cs->sent_gw_query = true; + garp.wake_ts[AS_QUERY_GW_SEND] = -1; return ARPR_OK; } +// 1 == not yet time, 0 == timed out, success, -1 == timed out, failure +int arp_query_gateway_timeout(struct client_state_t cs[static 1], long long nowts) +{ + long long rtts = garp.wake_ts[AS_QUERY_GW_SEND]; + if (rtts == -1) return 0; + if (nowts < rtts) return 1; + return arp_query_gateway(cs) == ARPR_OK ? 0 : -1; +} + int arp_announce(struct client_state_t cs[static 1]) { if (cs->sent_first_announce && cs->sent_second_announce) { diff --git a/src/arp.h b/src/arp.h index 2279f55..409c3dc 100644 --- a/src/arp.h +++ b/src/arp.h @@ -63,6 +63,7 @@ typedef enum { AS_ANNOUNCE, // Announcing our MAC/IP mapping to ethernet peers. AS_COLLISION_CHECK, // Checking to see if another host has our IP before // accepting a new lease. + AS_QUERY_GW_SEND, // Sending arp_ping to query the gateway MAC. AS_GW_CHECK, // Seeing if the default GW still exists on the local // segment after the hardware link was lost. AS_GW_QUERY, // Finding the default GW MAC address. @@ -120,6 +121,7 @@ int arp_do_collision_check(struct client_state_t cs[static 1]); int arp_collision_timeout(struct client_state_t cs[static 1], long long nowts); int arp_query_gateway(struct client_state_t cs[static 1]); +int arp_query_gateway_timeout(struct client_state_t cs[static 1], long long nowts); int arp_announce(struct client_state_t cs[static 1]); int arp_announce_timeout(struct client_state_t cs[static 1], long long nowts); diff --git a/src/state.c b/src/state.c index 558039e..a32754d 100644 --- a/src/state.c +++ b/src/state.c @@ -537,8 +537,7 @@ int dhcp_handle(struct client_state_t cs[static 1], long long nowts, if (arp_timeout) { int r = arp_collision_timeout(cs, nowts); if (r == ARPR_FREE) { - if (arp_query_gateway(cs) == ARPR_OK) - cs->sent_gw_query = true; // XXX: Handle the false case + arp_query_gateway(cs); arp_announce(cs); break; } else if (r == ARPR_OK) { @@ -647,7 +646,9 @@ int dhcp_handle(struct client_state_t cs[static 1], long long nowts, arp_defense_timeout(cs, nowts); else arp_announce_timeout(cs, nowts); - if (!cs->got_router_arp || !cs->got_server_arp) { + if (!cs->sent_gw_query) + arp_query_gateway_timeout(cs, nowts); + else if (!cs->got_router_arp || !cs->got_server_arp) { int r = arp_gw_query_timeout(cs, nowts); if (r == ARPR_OK) { } else if (r == ARPR_FAIL) {