From 65f5692a12caadf375677414e633c955c9bec0a0 Mon Sep 17 00:00:00 2001
From: Leo Ruan <tingquan.ruan@cn.bosch.com>
Date: Thu, 25 Jul 2024 16:37:11 +0800
Subject: [PATCH] IPv4LL: Restart ARP probling on address conflict (#340)

* IPv4LL: Restart ARP probling on address conflict

When IPv4LL address conflict is detected, it is failed to restart IPv4LL
since IPv4LL is running. The commit fixes the problem by restarting ARP
probing instead of restarting IPv4LL.

---------

Co-authored-by: Roy Marples <roy@marples.name>
---
 src/ipv4ll.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/src/ipv4ll.c b/src/ipv4ll.c
index 89b3dce6..43974a80 100644
--- a/src/ipv4ll.c
+++ b/src/ipv4ll.c
@@ -50,6 +50,8 @@
 #include "sa.h"
 #include "script.h"
 
+static void ipv4ll_start_arp(void *arg);
+
 static const struct in_addr inaddr_llmask = {
 	.s_addr = HTONL(LINKLOCAL_MASK)
 };
@@ -275,7 +277,7 @@ ipv4ll_found(struct interface *ifp)
 	eloop_timeout_add_sec(ifp->ctx->eloop,
 	    state->conflicts >= MAX_CONFLICTS ?
 	    RATE_LIMIT_INTERVAL : PROBE_WAIT,
-	    ipv4ll_start, ifp);
+	    ipv4ll_start_arp, ifp);
 }
 
 static void
@@ -290,7 +292,7 @@ ipv4ll_defend_failed(struct interface *ifp)
 	rt_build(ifp->ctx, AF_INET);
 	script_runreason(ifp, "IPV4LL");
 	ipv4ll_pickaddr(ifp);
-	ipv4ll_start(ifp);
+	ipv4ll_start_arp(ifp);
 }
 
 #ifndef KERNEL_RFC5227
@@ -323,9 +325,6 @@ ipv4ll_start(void *arg)
 	struct ipv4ll_state *state;
 	struct ipv4_addr *ia;
 	bool repick;
-#ifndef KERNEL_RFC5227
-	struct arp_state *astate;
-#endif
 
 	if ((state = IPV4LL_STATE(ifp)) == NULL) {
 		ifp->if_data[IF_DATA_IPV4LL] = calloc(1, sizeof(*state));
@@ -407,9 +406,21 @@ ipv4ll_start(void *arg)
 			ipv4ll_pickaddr(ifp);
 	}
 
+	ipv4ll_start_arp(ifp);
+}
+
+static void
+ipv4ll_start_arp(void *arg)
+{
+	struct interface *ifp = arg;
 #ifdef KERNEL_RFC5227
 	ipv4ll_not_found(ifp);
 #else
+	struct ipv4ll_state *state;
+	struct arp_state *astate;
+
+	state = IPV4LL_STATE(ifp);
+
 	ipv4ll_freearp(ifp);
 	state->arp = astate = arp_new(ifp, &state->pickedaddr);
 	if (state->arp == NULL)