Module Name:    src
Committed By:   roy
Date:           Tue Jun 11 12:08:29 UTC 2013

Modified Files:
        src/sys/net: if.c
        src/sys/netinet6: in6.c in6.h nd6_rtr.c

Log Message:
When an interface link state changes to down, mark all attached IPv6
addresses as detached.
Likewise, when the link state changes to up, mark all detached IPv6
as tentative and start DAD on them.

Advertised router reachability now checks that link state is not down.
This means that when an interface link state changes, the default IPv6
router may change as well.


To generate a diff of this commit:
cvs rdiff -u -r1.262 -r1.263 src/sys/net/if.c
cvs rdiff -u -r1.163 -r1.164 src/sys/netinet6/in6.c
cvs rdiff -u -r1.71 -r1.72 src/sys/netinet6/in6.h
cvs rdiff -u -r1.87 -r1.88 src/sys/netinet6/nd6_rtr.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if.c
diff -u src/sys/net/if.c:1.262 src/sys/net/if.c:1.263
--- src/sys/net/if.c:1.262	Sun Mar 10 19:46:12 2013
+++ src/sys/net/if.c	Tue Jun 11 12:08:29 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.c,v 1.262 2013/03/10 19:46:12 christos Exp $	*/
+/*	$NetBSD: if.c,v 1.263 2013/06/11 12:08:29 roy Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.262 2013/03/10 19:46:12 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.263 2013/06/11 12:08:29 roy Exp $");
 
 #include "opt_inet.h"
 
@@ -1337,15 +1337,52 @@ link_rtrequest(int cmd, struct rtentry *
 void
 if_link_state_change(struct ifnet *ifp, int link_state)
 {
+	int old_link_state;
+
 	if (ifp->if_link_state == link_state)
 		return;
+
+	old_link_state = ifp->if_link_state;
 	ifp->if_link_state = link_state;
+#ifdef DEBUG
+	log(LOG_DEBUG, "%s: link state %s (was %s)\n", ifp->if_xname,
+		link_state == LINK_STATE_UP ? "UP" :
+		link_state == LINK_STATE_DOWN ? "DOWN" :
+		"UNKNOWN",
+		old_link_state == LINK_STATE_UP ? "UP" :
+		old_link_state == LINK_STATE_DOWN ? "DOWN" :
+		"UNKNOWN");
+#endif
+
+#ifdef INET6
+	/*
+	 * When going from UNKNOWN to UP, we need to mark existing
+	 * IPv6 addresses as tentative and restart DAD as we may have
+	 * erroneously not found a duplicate.
+	 *
+	 * This needs to happen before rt_ifmsg to avoid a race where
+	 * listeners would have an address and expect it to work right
+	 * away.
+	 */
+	if (link_state == LINK_STATE_UP &&
+	    old_link_state == LINK_STATE_UNKNOWN)
+		in6_if_down(ifp);
+#endif
+
 	/* Notify that the link state has changed. */
 	rt_ifmsg(ifp);
+
 #if NCARP > 0
 	if (ifp->if_carp)
 		carp_carpdev_state(ifp);
 #endif
+
+#ifdef INET6
+	if (link_state == LINK_STATE_DOWN)
+		in6_if_down(ifp);
+	else if (link_state == LINK_STATE_UP)
+		in6_if_up(ifp);
+#endif
 }
 
 /*
@@ -1368,6 +1405,9 @@ if_down(struct ifnet *ifp)
 		carp_carpdev_state(ifp);
 #endif
 	rt_ifmsg(ifp);
+#ifdef INET6
+	in6_if_down(ifp);
+#endif
 }
 
 /*

Index: src/sys/netinet6/in6.c
diff -u src/sys/netinet6/in6.c:1.163 src/sys/netinet6/in6.c:1.164
--- src/sys/netinet6/in6.c:1.163	Wed May 29 12:07:58 2013
+++ src/sys/netinet6/in6.c	Tue Jun 11 12:08:29 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6.c,v 1.163 2013/05/29 12:07:58 roy Exp $	*/
+/*	$NetBSD: in6.c,v 1.164 2013/06/11 12:08:29 roy Exp $	*/
 /*	$KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.163 2013/05/29 12:07:58 roy Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.164 2013/06/11 12:08:29 roy Exp $");
 
 #include "opt_inet.h"
 #include "opt_pfil_hooks.h"
@@ -1078,14 +1078,6 @@ in6_update_ifa1(struct ifnet *ifp, struc
 	 * configure address flags.
 	 */
 	ia->ia6_flags = ifra->ifra_flags;
-	/*
-	 * backward compatibility - if IN6_IFF_DEPRECATED is set from the
-	 * userland, make it deprecated.
-	 */
-	if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) {
-		ia->ia6_lifetime.ia6t_pltime = 0;
-		ia->ia6_lifetime.ia6t_preferred = time_second;
-	}
 
 	/*
 	 * Make the address tentative before joining multicast addresses,
@@ -1093,13 +1085,24 @@ in6_update_ifa1(struct ifnet *ifp, struc
 	 * source address.
 	 */
 	ia->ia6_flags &= ~IN6_IFF_DUPLICATED;	/* safety */
-	if (hostIsNew && in6if_do_dad(ifp)) 
+	if (ifp->if_link_state == LINK_STATE_DOWN) {
+		ia->ia6_flags |= IN6_IFF_DETACHED;
+		ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
+	} else if (hostIsNew && in6if_do_dad(ifp))
 		ia->ia6_flags |= IN6_IFF_TENTATIVE;
 
+	/*
+	 * backward compatibility - if IN6_IFF_DEPRECATED is set from the
+	 * userland, make it deprecated.
+	 */
+	if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) {
+		ia->ia6_lifetime.ia6t_pltime = 0;
+		ia->ia6_lifetime.ia6t_preferred = time_second;
+	}
+
 	/* reset the interface and routing table appropriately. */
 	if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0)
 		goto unlink;
-
 	/*
 	 * We are done if we have simply modified an existing address.
 	 */
@@ -2167,10 +2170,29 @@ in6_if_up(struct ifnet *ifp)
 	struct ifaddr *ifa;
 	struct in6_ifaddr *ia;
 
+	/* Ensure it's sane to run DAD */
+	if (ifp->if_link_state == LINK_STATE_DOWN)
+		return;
+	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+		return;
+
 	IFADDR_FOREACH(ifa, ifp) {
 		if (ifa->ifa_addr->sa_family != AF_INET6)
 			continue;
 		ia = (struct in6_ifaddr *)ifa;
+
+		/* If detached then mark as tentative */
+		if (ia->ia6_flags & IN6_IFF_DETACHED) {
+			ia->ia6_flags &= ~IN6_IFF_DETACHED;
+			if (in6if_do_dad(ifp)) {
+				ia->ia6_flags |= IN6_IFF_TENTATIVE;
+				nd6log((LOG_ERR, "in6_if_up: "
+				    "%s marked tentative\n",
+				    ip6_sprintf(&ia->ia_addr.sin6_addr)));
+			} else if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0)
+				nd6_newaddrmsg(ifa);
+		}
+
 		if (ia->ia6_flags & IN6_IFF_TENTATIVE) {
 			/*
 			 * The TENTATIVE flag was likely set by hand
@@ -2188,6 +2210,48 @@ in6_if_up(struct ifnet *ifp)
 	 * special cases, like 6to4, are handled in in6_ifattach
 	 */
 	in6_ifattach(ifp, NULL);
+
+	/* Restore any detached prefixes */
+	pfxlist_onlink_check();
+}
+
+/*
+ * Mark all addresses as detached.
+ */
+void
+in6_if_down(struct ifnet *ifp)
+{
+	struct ifaddr *ifa;
+	struct in6_ifaddr *ia;
+
+	IFADDR_FOREACH(ifa, ifp) {
+		if (ifa->ifa_addr->sa_family != AF_INET6)
+			continue;
+		ia = (struct in6_ifaddr *)ifa;
+
+		/* Stop DAD processing */
+		nd6_dad_stop(ifa);
+
+		/*
+		 * Mark the address as detached.
+		 * This satisfies RFC4862 Section 5.3, but we should apply
+		 * this logic to all addresses to be a good citizen and
+		 * avoid potential duplicated addresses.
+		 * When the interface comes up again, detached addresses
+		 * are marked tentative and DAD commences.
+		 */
+		if (!(ia->ia6_flags & IN6_IFF_DETACHED)) {
+			nd6log((LOG_DEBUG, "in6_if_down: "
+			    "%s marked detached\n",
+			    ip6_sprintf(&ia->ia_addr.sin6_addr)));
+			ia->ia6_flags |= IN6_IFF_DETACHED;
+			ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
+			nd6_newaddrmsg(ifa);
+		}
+	}
+
+	/* Any prefixes on this interface should be detached as well */
+	pfxlist_onlink_check();
 }
 
 int

Index: src/sys/netinet6/in6.h
diff -u src/sys/netinet6/in6.h:1.71 src/sys/netinet6/in6.h:1.72
--- src/sys/netinet6/in6.h:1.71	Sat Apr 27 21:35:24 2013
+++ src/sys/netinet6/in6.h	Tue Jun 11 12:08:29 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6.h,v 1.71 2013/04/27 21:35:24 joerg Exp $	*/
+/*	$NetBSD: in6.h,v 1.72 2013/06/11 12:08:29 roy Exp $	*/
 /*	$KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $	*/
 
 /*
@@ -701,6 +701,7 @@ int	in6_localaddr(const struct in6_addr 
 int	in6_addrscope(const struct in6_addr *);
 struct	in6_ifaddr *in6_ifawithifp(struct ifnet *, struct in6_addr *);
 extern void in6_if_up(struct ifnet *);
+extern void in6_if_down(struct ifnet *);
 #ifndef __FreeBSD__
 extern int in6_src_sysctl(void *, size_t *, void *, size_t);
 #endif

Index: src/sys/netinet6/nd6_rtr.c
diff -u src/sys/netinet6/nd6_rtr.c:1.87 src/sys/netinet6/nd6_rtr.c:1.88
--- src/sys/netinet6/nd6_rtr.c:1.87	Tue May 21 08:37:27 2013
+++ src/sys/netinet6/nd6_rtr.c	Tue Jun 11 12:08:29 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: nd6_rtr.c,v 1.87 2013/05/21 08:37:27 roy Exp $	*/
+/*	$NetBSD: nd6_rtr.c,v 1.88 2013/06/11 12:08:29 roy Exp $	*/
 /*	$KAME: nd6_rtr.c,v 1.95 2001/02/07 08:09:47 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.87 2013/05/21 08:37:27 roy Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.88 2013/06/11 12:08:29 roy Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -1407,7 +1407,8 @@ find_pfxlist_reachable_router(struct nd_
 		if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
 		    pfxrtr->router->ifp)) &&
 		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
-		    ND6_IS_LLINFO_PROBREACH(ln))
+		    ND6_IS_LLINFO_PROBREACH(ln) &&
+		    pfxrtr->router->ifp->if_link_state != LINK_STATE_DOWN)
 			break;	/* found */
 	}
 

Reply via email to