Module Name:    src
Committed By:   dyoung
Date:           Thu Apr 22 20:05:15 UTC 2010

Modified Files:
        src/sys/netinet6: in6.c

Log Message:
When choosing IPv6 source addresses, respect the ifaddr preference
level such as one might set with 'ifconfig xx0 inet6 <address>
preference <pref>'.  I've been running this for many months without
any problems.


To generate a diff of this commit:
cvs rdiff -u -r1.155 -r1.156 src/sys/netinet6/in6.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/netinet6/in6.c
diff -u src/sys/netinet6/in6.c:1.155 src/sys/netinet6/in6.c:1.156
--- src/sys/netinet6/in6.c:1.155	Wed Apr  7 22:59:15 2010
+++ src/sys/netinet6/in6.c	Thu Apr 22 20:05:15 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6.c,v 1.155 2010/04/07 22:59:15 oki Exp $	*/
+/*	$NetBSD: in6.c,v 1.156 2010/04/22 20:05:15 dyoung 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.155 2010/04/07 22:59:15 oki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.156 2010/04/22 20:05:15 dyoung Exp $");
 
 #include "opt_inet.h"
 #include "opt_pfil_hooks.h"
@@ -1792,6 +1792,14 @@
 	return error;
 }
 
+static struct ifaddr *
+bestifa(struct ifaddr *best_ifa, struct ifaddr *ifa)
+{
+	if (best_ifa == NULL || best_ifa->ifa_preference < ifa->ifa_preference)
+		return ifa;
+	return best_ifa;
+}
+
 /*
  * Find an IPv6 interface link-local address specific to an interface.
  */
@@ -1809,10 +1817,7 @@
 			continue;
 		if ((((struct in6_ifaddr *)ifa)->ia6_flags & ignoreflags) != 0)
 			continue;
-		if (best_ifa == NULL)
-			best_ifa = ifa;
-		else if (best_ifa->ifa_preference < ifa->ifa_preference)
-			best_ifa = ifa;
+		best_ifa = bestifa(best_ifa, ifa);
 	}
 
 	return (struct in6_ifaddr *)best_ifa;
@@ -1825,18 +1830,28 @@
 struct in6_ifaddr *
 in6ifa_ifpwithaddr(const struct ifnet *ifp, const struct in6_addr *addr)
 {
-	struct ifaddr *ifa;
+	struct ifaddr *best_ifa = NULL, *ifa;
 
 	IFADDR_FOREACH(ifa, ifp) {
 		if (ifa->ifa_addr == NULL)
 			continue;	/* just for safety */
 		if (ifa->ifa_addr->sa_family != AF_INET6)
 			continue;
-		if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
-			break;
+		if (!IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
+			continue;
+		best_ifa = bestifa(best_ifa, ifa);
 	}
 
-	return (struct in6_ifaddr *)ifa;
+	return (struct in6_ifaddr *)best_ifa;
+}
+
+static struct in6_ifaddr *
+bestia(struct in6_ifaddr *best_ia, struct in6_ifaddr *ia)
+{
+	if (best_ia == NULL ||
+	    best_ia->ia_ifa.ifa_preference < ia->ia_ifa.ifa_preference)
+		return ia;
+	return best_ia;
 }
 
 /*
@@ -1847,7 +1862,7 @@
 in6ifa_ifplocaladdr(const struct ifnet *ifp, const struct in6_addr *addr)
 {
 	struct ifaddr *ifa;
-	struct in6_ifaddr *ia;
+	struct in6_ifaddr *best_ia = NULL, *ia;
 
 	IFADDR_FOREACH(ifa, ifp) {
 		if (ifa->ifa_addr == NULL)
@@ -1855,13 +1870,14 @@
 		if (ifa->ifa_addr->sa_family != AF_INET6)
 			continue;
 		ia = (struct in6_ifaddr *)ifa;
-		if (IN6_ARE_MASKED_ADDR_EQUAL(addr,
+		if (!IN6_ARE_MASKED_ADDR_EQUAL(addr,
 				&ia->ia_addr.sin6_addr,
 				&ia->ia_prefixmask.sin6_addr))
-			return ia;
+			continue;
+		best_ia = bestia(best_ia, ia);
 	}
 
-	return NULL;
+	return best_ia;
 }
 
 /*
@@ -2043,7 +2059,7 @@
 {
 	int dst_scope =	in6_addrscope(dst), blen = -1, tlen;
 	struct ifaddr *ifa;
-	struct in6_ifaddr *besta = 0;
+	struct in6_ifaddr *best_ia = NULL, *ia;
 	struct in6_ifaddr *dep[2];	/* last-resort: deprecated */
 
 	dep[0] = dep[1] = NULL;
@@ -2057,54 +2073,60 @@
 	IFADDR_FOREACH(ifa, ifp) {
 		if (ifa->ifa_addr->sa_family != AF_INET6)
 			continue;
-		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
+		ia = (struct in6_ifaddr *)ifa;
+		if (ia->ia6_flags & IN6_IFF_ANYCAST)
 			continue; /* XXX: is there any case to allow anycast? */
-		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
+		if (ia->ia6_flags & IN6_IFF_NOTREADY)
 			continue; /* don't use this interface */
-		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
+		if (ia->ia6_flags & IN6_IFF_DETACHED)
 			continue;
-		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
+		if (ia->ia6_flags & IN6_IFF_DEPRECATED) {
 			if (ip6_use_deprecated)
-				dep[0] = (struct in6_ifaddr *)ifa;
+				dep[0] = ia;
 			continue;
 		}
 
-		if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
-			/*
-			 * call in6_matchlen() as few as possible
-			 */
-			if (besta) {
-				if (blen == -1)
-					blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
-				tlen = in6_matchlen(IFA_IN6(ifa), dst);
-				if (tlen > blen) {
-					blen = tlen;
-					besta = (struct in6_ifaddr *)ifa;
-				}
-			} else
-				besta = (struct in6_ifaddr *)ifa;
+		if (dst_scope != in6_addrscope(IFA_IN6(ifa)))
+			continue;
+		/*
+		 * call in6_matchlen() as few as possible
+		 */
+		if (best_ia == NULL) {
+			best_ia = ia;
+			continue;
 		}
+		if (blen == -1)
+			blen = in6_matchlen(&best_ia->ia_addr.sin6_addr, dst);
+		tlen = in6_matchlen(IFA_IN6(ifa), dst);
+		if (tlen > blen) {
+			blen = tlen;
+			best_ia = ia;
+		} else if (tlen == blen)
+			best_ia = bestia(best_ia, ia);
 	}
-	if (besta)
-		return besta;
+	if (best_ia != NULL)
+		return best_ia;
 
 	IFADDR_FOREACH(ifa, ifp) {
 		if (ifa->ifa_addr->sa_family != AF_INET6)
 			continue;
-		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
+		ia = (struct in6_ifaddr *)ifa;
+		if (ia->ia6_flags & IN6_IFF_ANYCAST)
 			continue; /* XXX: is there any case to allow anycast? */
-		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
+		if (ia->ia6_flags & IN6_IFF_NOTREADY)
 			continue; /* don't use this interface */
-		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
+		if (ia->ia6_flags & IN6_IFF_DETACHED)
 			continue;
-		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
+		if (ia->ia6_flags & IN6_IFF_DEPRECATED) {
 			if (ip6_use_deprecated)
 				dep[1] = (struct in6_ifaddr *)ifa;
 			continue;
 		}
 
-		return (struct in6_ifaddr *)ifa;
+		best_ia = bestia(best_ia, ia);
 	}
+	if (best_ia != NULL)
+		return best_ia;
 
 	/* use the last-resort values, that are, deprecated addresses */
 	if (dep[0])

Reply via email to