changeset 5237:65cef5f96919 draft

IPv4LL: Fix for prior on NetBSD at least.
author Roy Marples <roy@marples.name>
date Wed, 20 May 2020 12:17:00 +0100
parents 40c8b6fa2033
children 73659576d485
files src/arp.c src/arp.h src/ipv4ll.c src/ipv4ll.h
diffstat 4 files changed, 57 insertions(+), 113 deletions(-) [+]
line wrap: on
line diff
--- a/src/arp.c	Tue May 19 16:44:49 2020 +0000
+++ b/src/arp.c	Wed May 20 12:17:00 2020 +0100
@@ -509,7 +509,7 @@
 		if (iap == NULL)
 			continue;
 #ifdef IN_IFF_NOTUSEABLE
-		if (!(iap->addr_flags & IN_IFF_NOTUSEABLE))
+		if (iap->addr_flags & IN_IFF_NOTUSEABLE)
 			continue;
 #endif
 		if (iff != NULL && iff->metric < ifp->metric)
--- a/src/arp.h	Tue May 19 16:44:49 2020 +0000
+++ b/src/arp.h	Wed May 20 12:17:00 2020 +0100
@@ -47,7 +47,8 @@
 
 #ifdef IN_IFF_DUPLICATED
 /* NetBSD gained RFC 5227 support in the kernel.
- * This means dhcpcd doesn't need ARP except for ARPing support. */
+ * This means dhcpcd doesn't need ARP except for ARPing support
+ * and ARP announcing an address. */
 #if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 799003900
 #define KERNEL_RFC5227
 #endif
--- a/src/ipv4ll.c	Tue May 19 16:44:49 2020 +0000
+++ b/src/ipv4ll.c	Wed May 20 12:17:00 2020 +0100
@@ -57,8 +57,6 @@
 	.s_addr = HTONL(LINKLOCAL_BCAST)
 };
 
-static void ipv4ll_start1(struct interface *, struct arp_state *);
-
 static in_addr_t
 ipv4ll_pickaddr(struct interface *ifp)
 {
@@ -170,17 +168,19 @@
 	return 5;
 }
 
+#ifndef KERNEL_RFC5227
 static void
 ipv4ll_announced_arp(struct arp_state *astate)
 {
 	struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
 
 	state->conflicts = 0;
-#ifdef KERNEL_RFC5227
 	arp_free(astate);
-#endif
+	if (state->arp == astate)
+		state->arp = NULL;
 }
 
+/* This is the callback by ARP freeing */
 static void
 ipv4ll_arpfree(struct arp_state *astate)
 {
@@ -191,23 +191,32 @@
 		state->arp = NULL;
 }
 
+/* This is us freeing any ARP state */
+static void
+ipv4ll_freearp(struct interface *ifp)
+{
+	struct ipv4ll_state *state;
+
+	state = IPV4LL_STATE(ifp);
+	if (state == NULL || state->arp == NULL)
+		return;
+
+	eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp);
+	arp_free(state->arp);
+	state->arp = NULL;
+}
+#else
+#define	ipv4ll_freearp(ifp)
+#endif
+
 static void
 ipv4ll_not_found(struct interface *ifp)
 {
 	struct ipv4ll_state *state;
 	struct ipv4_addr *ia;
-#ifdef KERNEL_RFC5227
-	struct arp_state *astate;
-	bool new_addr;
-#endif
 
 	state = IPV4LL_STATE(ifp);
-	assert(state != NULL);
-
 	ia = ipv4_iffindaddr(ifp, &state->pickedaddr, &inaddr_llmask);
-#ifdef KERNEL_RFC5227
-	new_addr = ia == NULL;
-#endif
 #ifdef IN_IFF_NOTREADY
 	if (ia == NULL || ia->addr_flags & IN_IFF_NOTREADY)
 #endif
@@ -227,6 +236,7 @@
 		return;
 	logdebugx("%s: DAD completed for %s", ifp->name, ia->saddr);
 #endif
+
 test:
 	state->addr = ia;
 	state->down = false;
@@ -236,41 +246,17 @@
 		return;
 	}
 	rt_build(ifp->ctx, AF_INET);
-#ifdef KERNEL_RFC5227
-	if (!new_addr) {
-		astate = arp_new(ifp, &ia->addr);
-		if (ifp->ctx->options & DHCPCD_FORKED)
-			return;
-		if (astate != NULL) {
-			astate->announced_cb = ipv4ll_announced_arp;
-			astate->free_cb = ipv4ll_arpfree;
-			arp_announce(astate);
-		}
-	}
-#else
-	arp_announce(state->arp);
-#endif
+	arp_announceaddr(ifp->ctx, &ia->addr);
 	script_runreason(ifp, "IPV4LL");
 	dhcpcd_daemonise(ifp->ctx);
 }
 
 static void
-ipv4ll_startifp(void *arg)
-{
-	struct interface *ifp = arg;
-	struct ipv4ll_state *state;
-
-	state = IPV4LL_STATE(ifp);
-	ipv4ll_start1(ifp, state->arp);
-}
-
-static void
 ipv4ll_found(struct interface *ifp)
 {
 	struct ipv4ll_state *state = IPV4LL_STATE(ifp);
 
-	if (state->arp != NULL)
-		arp_cancel(state->arp);
+	ipv4ll_freearp(ifp);
 	if (++state->conflicts == MAX_CONFLICTS)
 		logerrx("%s: failed to acquire an IPv4LL address",
 		    ifp->name);
@@ -278,7 +264,7 @@
 	eloop_timeout_add_sec(ifp->ctx->eloop,
 	    state->conflicts >= MAX_CONFLICTS ?
 	    RATE_LIMIT_INTERVAL : PROBE_WAIT,
-	    ipv4ll_startifp, ifp);
+	    ipv4ll_start, ifp);
 }
 
 static void
@@ -286,62 +272,49 @@
 {
 	struct ipv4ll_state *state = IPV4LL_STATE(ifp);
 
-	if (state->arp != NULL)
-		arp_cancel(state->arp);
+	ipv4ll_freearp(ifp);
 	ipv4_deladdr(state->addr, 1);
-	state->down = true;
 	state->addr = NULL;
 	rt_build(ifp->ctx, AF_INET);
 	script_runreason(ifp, "IPV4LL");
 	state->pickedaddr.s_addr = ipv4ll_pickaddr(ifp);
-	ipv4ll_start1(ifp, state->arp);
+	ipv4ll_start(ifp);
 }
 
 #ifndef KERNEL_RFC5227
 static void
 ipv4ll_not_found_arp(struct arp_state *astate)
 {
-	struct interface *ifp;
-	struct ipv4ll_state *state;
 
-	assert(astate != NULL);
-	assert(astate->iface != NULL);
-
-	ifp = astate->iface;
-	state = IPV4LL_STATE(ifp);
-	assert(state != NULL);
-	assert(state->arp == astate);
-	ipv4ll_not_found(ifp);
+	ipv4ll_not_found(astate->iface);
 }
 
 static void
 ipv4ll_found_arp(struct arp_state *astate, __unused const struct arp_msg *amsg)
 {
-	struct interface *ifp = astate->iface;
-	struct ipv4ll_state *state = IPV4LL_STATE(ifp);
 
-	assert(state->arp == astate);
-	ipv4ll_found(ifp);
+	ipv4ll_found(astate->iface);
 }
 
 static void
 ipv4ll_defend_failed_arp(struct arp_state *astate)
 {
-	struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
 
-	assert(state->arp == astate);
 	ipv4ll_defend_failed(astate->iface);
 }
 #endif
 
-static void
-ipv4ll_start1(struct interface *ifp, struct arp_state *astate)
+void
+ipv4ll_start(void *arg)
 {
+	struct interface *ifp = arg;
 	struct ipv4ll_state *state;
 	struct ipv4_addr *ia;
 	bool repick;
+#ifndef KERNEL_RFC5227
+	struct arp_state *astate;
+#endif
 
-	assert(ifp != NULL);
 	if ((state = IPV4LL_STATE(ifp)) == NULL) {
 		ifp->if_data[IF_DATA_IPV4LL] = calloc(1, sizeof(*state));
 		if ((state = IPV4LL_STATE(ifp)) == NULL) {
@@ -377,26 +350,6 @@
 		state->seeded = true;
 	}
 
-#ifndef KERNEL_RFC5227
-	if (astate == NULL) {
-		if (state->arp != NULL)
-			return;
-		if ((astate = arp_new(ifp, NULL)) == NULL)
-			return;
-		astate->found_cb = ipv4ll_found_arp;
-		astate->not_found_cb = ipv4ll_not_found_arp;
-		astate->announced_cb = ipv4ll_announced_arp;
-		astate->defend_failed_cb = ipv4ll_defend_failed_arp;
-		astate->free_cb = ipv4ll_arpfree;
-		state->arp = astate;
-	} else
-		assert(state->arp == astate);
-#else
-	UNUSED(astate);
-#endif
-
-	state->down = true;
-
 	/* Find the previosuly used address. */
 	if (state->pickedaddr.s_addr != INADDR_ANY)
 		ia = ipv4_iffindaddr(ifp, &state->pickedaddr, NULL);
@@ -418,11 +371,9 @@
 #endif
 
 	state->addr = ia;
+	state->down = true;
 	if (ia != NULL) {
 		state->pickedaddr = ia->addr;
-#ifndef KERNEL_RFC5227
-		astate->addr = ia->addr;
-#endif
 #ifdef IN_IFF_TENTATIVE
 		if (ia->addr_flags & (IN_IFF_TENTATIVE | IN_IFF_DETACHED)) {
 			loginfox("%s: waiting for DAD to complete on %s",
@@ -440,9 +391,20 @@
 	loginfox("%s: probing for an IPv4LL address", ifp->name);
 	if (repick || state->pickedaddr.s_addr == INADDR_ANY)
 		state->pickedaddr.s_addr = ipv4ll_pickaddr(ifp);
+
 #ifndef KERNEL_RFC5227
-	astate->addr = state->pickedaddr;
+	ipv4ll_freearp(ifp);
+	state->arp = astate = arp_new(ifp, NULL);
+	if (state->arp == NULL)
+		return;
+
+	astate->found_cb = ipv4ll_found_arp;
+	astate->not_found_cb = ipv4ll_not_found_arp;
+	astate->announced_cb = ipv4ll_announced_arp;
+	astate->defend_failed_cb = ipv4ll_defend_failed_arp;
+	astate->free_cb = ipv4ll_arpfree;
 #endif
+
 #ifdef IN_IFF_DUPLICATED
 	ipv4ll_not_found(ifp);
 #else
@@ -451,26 +413,6 @@
 }
 
 void
-ipv4ll_start(void *arg)
-{
-
-	ipv4ll_start1(arg, NULL);
-}
-
-static void
-ipv4ll_freearp(struct interface *ifp)
-{
-	struct ipv4ll_state *state;
-
-	state = IPV4LL_STATE(ifp);
-	if (state == NULL || state->arp == NULL)
-		return;
-
-	eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp);
-	arp_free(state->arp);
-}
-
-void
 ipv4ll_drop(struct interface *ifp)
 {
 	struct ipv4ll_state *state;
@@ -516,6 +458,7 @@
 
 	if (state == NULL)
 		return;
+	ipv4ll_freearp(ifp);
 	state->pickedaddr.s_addr = INADDR_ANY;
 	state->seeded = false;
 }
@@ -587,9 +530,7 @@
 		ipv4ll_not_found(ifp);
 	else if (ia->addr_flags & IN_IFF_DUPLICATED) {
 		logerrx("%s: DAD detected %s", ifp->name, ia->saddr);
-#ifdef KERNEL_RFC5227
-		arp_freeaddr(ifp, &ia->addr);
-#endif
+		ipv4ll_freearp(ifp);
 		ipv4_deladdr(ia, 1);
 		state->addr = NULL;
 		rt_build(ifp->ctx, AF_INET);
--- a/src/ipv4ll.h	Tue May 19 16:44:49 2020 +0000
+++ b/src/ipv4ll.h	Wed May 20 12:17:00 2020 +0100
@@ -43,11 +43,13 @@
 struct ipv4ll_state {
 	struct in_addr pickedaddr;
 	struct ipv4_addr *addr;
-	struct arp_state *arp;
 	char randomstate[128];
 	bool seeded;
 	bool down;
 	size_t conflicts;
+#ifndef KERNEL_RFC5227
+	struct arp_state *arp;
+#endif
 };
 
 #define	IPV4LL_STATE(ifp)						       \