From 56920baef21f23307c3df9719914e75fe729e0b8 Mon Sep 17 00:00:00 2001
From: Steven Barth <steven@midlink.org>
Date: Fri, 31 May 2013 15:45:42 +0200
Subject: [PATCH] Work around false-positive DAD-hits

---
 src/odhcp6c.c | 12 +++++++++---
 src/odhcp6c.h |  1 +
 src/ra.c      | 14 +++++++++++---
 3 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/src/odhcp6c.c b/src/odhcp6c.c
index d70546b..4fefcd7 100644
--- a/src/odhcp6c.c
+++ b/src/odhcp6c.c
@@ -42,6 +42,7 @@ static size_t state_len[_STATE_MAX] = {0};
 static volatile int do_signal = 0;
 static int urandom_fd = -1, allow_slaac_only = 0;
 static bool bound = false, release = true;
+static time_t last_update = 0;
 
 
 int main(_unused int argc, char* const argv[])
@@ -357,9 +358,10 @@ bool odhcp6c_signal_process(void)
 {
 	if (do_signal == SIGIO) {
 		do_signal = 0;
+		bool ra_rtnled = ra_rtnl_process();
 		bool ra_updated = ra_process();
 
-		if (ra_rtnl_process() || (ra_updated && (bound || allow_slaac_only == 0)))
+		if (ra_rtnled || (ra_updated && (bound || allow_slaac_only == 0)))
 			script_call("ra-updated"); // Immediate process urgent events
 		else if (ra_updated && !bound && allow_slaac_only > 0)
 			script_delay_call("ra-updated", allow_slaac_only);
@@ -467,9 +469,7 @@ static void odhcp6c_expire_list(enum odhcp6c_state state, uint32_t elapsed)
 
 void odhcp6c_expire(void)
 {
-	static time_t last_update = 0;
 	time_t now = odhcp6c_get_milli_time() / 1000;
-
 	uint32_t elapsed = (last_update > 0) ? now - last_update : 0;
 	last_update = now;
 
@@ -481,6 +481,12 @@ void odhcp6c_expire(void)
 }
 
 
+uint32_t odhcp6c_elapsed(void)
+{
+	return odhcp6c_get_milli_time() / 1000 - last_update;
+}
+
+
 void odhcp6c_random(void *buf, size_t len)
 {
 	read(urandom_fd, buf, len);
diff --git a/src/odhcp6c.h b/src/odhcp6c.h
index b0a1980..2e7107c 100644
--- a/src/odhcp6c.h
+++ b/src/odhcp6c.h
@@ -244,3 +244,4 @@ void odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new);
 void odhcp6c_update_entry_safe(enum odhcp6c_state state, struct odhcp6c_entry *new, uint32_t safe);
 
 void odhcp6c_expire(void);
+uint32_t odhcp6c_elapsed(void);
diff --git a/src/ra.c b/src/ra.c
index 24c99c5..1b2f729 100644
--- a/src/ra.c
+++ b/src/ra.c
@@ -155,12 +155,16 @@ static bool ra_deduplicate(const struct in6_addr *any, uint8_t length)
 bool ra_rtnl_process(void)
 {
 	bool found = false;
+	uint32_t elapsed = odhcp6c_elapsed();
 	uint8_t buf[8192];
 	while (true) {
 		ssize_t len = recv(rtnl_sock, buf, sizeof(buf), MSG_DONTWAIT);
 		if (len < 0)
 			break;
 
+		if (elapsed > 10)
+			continue;
+
 		for (struct nlmsghdr *nh = (struct nlmsghdr*)buf; NLMSG_OK(nh, (size_t)len);
 					nh = NLMSG_NEXT(nh, len)) {
 			struct ifaddrmsg *ifa = NLMSG_DATA(nh);
@@ -197,7 +201,6 @@ bool ra_process(void)
 	struct nd_router_advert *adv = (struct nd_router_advert*)buf;
 	struct odhcp6c_entry entry = {IN6ADDR_ANY_INIT, 0, 0, IN6ADDR_ANY_INIT, 0, 0};
 	const struct in6_addr any = IN6ADDR_ANY_INIT;
-	odhcp6c_expire();
 
 	while (true) {
 		struct sockaddr_in6 from;
@@ -214,7 +217,10 @@ bool ra_process(void)
 			rs_attempt = 0;
 		}
 
-		found = true;
+		if (!found) {
+			odhcp6c_expire();
+			found = true;
+		}
 		uint32_t router_valid = ntohs(adv->nd_ra_router_lifetime);
 
 		// Parse default route
@@ -308,6 +314,8 @@ bool ra_process(void)
 				entry[i].valid = router_valid;
 	}
 
-	odhcp6c_expire();
+	if (found)
+		odhcp6c_expire();
+
 	return found;
 }
-- 
2.39.5