git: b69c0082426d - stable/15 - nd6: Fix regeneration of temp addresses in detached state

From: Pouria Mousavizadeh Tehrani <pouria_at_FreeBSD.org>
Date: Thu, 01 Oct 2026 11:05:02 UTC
The branch stable/15 has been updated by pouria:

URL: https://cgit.FreeBSD.org/src/commit/?id=b69c0082426dc23553bff7dfc90b41e8a03cf6c8

commit b69c0082426dc23553bff7dfc90b41e8a03cf6c8
Author:     Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
AuthorDate: 2026-09-26 19:54:16 +0000
Commit:     Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
CommitDate: 2026-10-01 10:59:30 +0000

    nd6: Fix regeneration of temp addresses in detached state
    
    When an on-link prefix becomes detached, the kernel keeps
    generating new RFC 8981 temporary addresses for that prefix.
    Fix it by ignoring the detached addresses in regen_tmpaddr().
    While here, change its return type to bool.
    
    PR:             298533
    Discussed with: markj
    MFC after:      3 days
    Differential Revision:  https://reviews.freebsd.org/D60051
    
    (cherry picked from commit 61f98a98250da7bd2c80c6d93d0032961d7f2fad)
---
 sys/netinet6/nd6.c | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index 00df5efcef92..07527fabe341 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -153,7 +153,7 @@ static bool nd6_is_new_addr_neighbor(const struct sockaddr_in6 *,
 	struct ifnet *);
 static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *);
 static void nd6_slowtimo(void *);
-static int regen_tmpaddr(struct in6_ifaddr *);
+static bool regen_tmpaddr(struct in6_ifaddr *);
 static void nd6_free(struct llentry **, int);
 static void nd6_free_redirect(const struct llentry *);
 static void nd6_llinfo_timer(void *);
@@ -959,7 +959,7 @@ nd6_timer(void *arg)
 	CK_STAILQ_FOREACH_SAFE(ia6, &V_in6_ifaddrhead, ia_link, nia6) {
 		/* check address lifetime */
 		if (IFA6_IS_INVALID(ia6)) {
-			int regen = 0;
+			bool regen = false;
 
 			/*
 			 * If the expiring address is temporary, try
@@ -973,8 +973,8 @@ nd6_timer(void *arg)
 			 */
 			if (V_ip6_use_tempaddr &&
 			    (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
-				if (regen_tmpaddr(ia6) == 0)
-					regen = 1;
+				if (regen_tmpaddr(ia6))
+					regen = true;
 			}
 
 			in6_purgeaddr(&ia6->ia_ifa);
@@ -993,7 +993,7 @@ nd6_timer(void *arg)
 			if (V_ip6_use_tempaddr &&
 			    (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
 			    (oldflags & IN6_IFF_DEPRECATED) == 0) {
-				if (regen_tmpaddr(ia6) == 0) {
+				if (regen_tmpaddr(ia6)) {
 					/*
 					 * A new temporary address is
 					 * generated.
@@ -1094,7 +1094,7 @@ restart:
 /*
  * ia6 - deprecated/invalidated temporary address
  */
-static int
+static bool
 regen_tmpaddr(struct in6_ifaddr *ia6)
 {
 	struct ifaddr *ifa;
@@ -1103,6 +1103,11 @@ regen_tmpaddr(struct in6_ifaddr *ia6)
 
 	NET_EPOCH_ASSERT();
 
+	/* ignore detached prefixes */
+	if (ia6->ia6_ndpr == NULL ||
+	    (ia6->ia6_ndpr->ndpr_stateflags & NDPRF_DETACHED) != 0)
+		return (false);
+
 	ifp = ia6->ia_ifa.ifa_ifp;
 	CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 		struct in6_ifaddr *it6;
@@ -1112,12 +1117,13 @@ regen_tmpaddr(struct in6_ifaddr *ia6)
 
 		it6 = (struct in6_ifaddr *)ifa;
 
-		/* ignore no autoconf addresses. */
-		if ((it6->ia6_flags & IN6_IFF_AUTOCONF) == 0)
+		/* ignore detached or no autoconf addresses. */
+		if ((it6->ia6_flags &
+		    (IN6_IFF_AUTOCONF | IN6_IFF_DETACHED)) != IN6_IFF_AUTOCONF)
 			continue;
 
 		/* ignore autoconf addresses with different prefixes. */
-		if (it6->ia6_ndpr == NULL || it6->ia6_ndpr != ia6->ia6_ndpr)
+		if (it6->ia6_ndpr != ia6->ia6_ndpr)
 			continue;
 
 		/*
@@ -1152,13 +1158,13 @@ regen_tmpaddr(struct in6_ifaddr *ia6)
 			ifa_free(&public_ifa6->ia_ifa);
 			log(LOG_NOTICE, "regen_tmpaddr: failed to create a new"
 			    " tmp addr,errno=%d\n", e);
-			return (-1);
+			return (false);
 		}
 		ifa_free(&public_ifa6->ia_ifa);
-		return (0);
+		return (true);
 	}
 
-	return (-1);
+	return (false);
 }
 
 /*