Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/netinet6 When choosing IPv6 source addresses, respect th...



details:   https://anonhg.NetBSD.org/src/rev/a77b558858d4
branches:  trunk
changeset: 754176:a77b558858d4
user:      dyoung <dyoung%NetBSD.org@localhost>
date:      Thu Apr 22 20:05:15 2010 +0000

description:
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.

diffstat:

 sys/netinet6/in6.c |  104 ++++++++++++++++++++++++++++++++--------------------
 1 files changed, 63 insertions(+), 41 deletions(-)

diffs (201 lines):

diff -r 2564d946ad46 -r a77b558858d4 sys/netinet6/in6.c
--- a/sys/netinet6/in6.c        Thu Apr 22 19:15:23 2010 +0000
+++ b/sys/netinet6/in6.c        Thu Apr 22 20:05:15 2010 +0000
@@ -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])



Home | Main Index | Thread Index | Old Index