Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 26 Aug 2009 21:32:51 +0000 (UTC)
From:      Qing Li <qingli@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r196569 - head/sys/netinet6
Message-ID:  <200908262132.n7QLWpMt075306@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: qingli
Date: Wed Aug 26 21:32:50 2009
New Revision: 196569
URL: http://svn.freebsd.org/changeset/base/196569

Log:
  When multiple interfaces exist in the system, with each interface having
  an IPv6 address assigned to it, and if an incoming packet received on
  one interface has a packet destination address that belongs to another
  interface, the routing table is consulted to determine how to reach this
  packet destination. Since the packet destination is an interface address,
  the route table will return a host route with the loopback interface as
  rt_ifp. The input code must recognize this fact, instead of using the
  loopback interface, the input code performs a search to find the right
  interface that owns the given IPv6 address.
  
  Reviewed by:	bz, gnn, kmacy
  MFC after:	immediately

Modified:
  head/sys/netinet6/ip6_input.c

Modified: head/sys/netinet6/ip6_input.c
==============================================================================
--- head/sys/netinet6/ip6_input.c	Wed Aug 26 21:14:28 2009	(r196568)
+++ head/sys/netinet6/ip6_input.c	Wed Aug 26 21:32:50 2009	(r196569)
@@ -628,8 +628,27 @@ passin:
 	    &rt6_key(rin6.ro_rt)->sin6_addr)
 #endif
 	    rin6.ro_rt->rt_ifp->if_type == IFT_LOOP) {
-		struct in6_ifaddr *ia6 =
-			(struct in6_ifaddr *)rin6.ro_rt->rt_ifa;
+		int free_ia6 = 0;
+		struct in6_ifaddr *ia6;
+
+		/*
+		 * found the loopback route to the interface address
+		 */
+		if (rin6.ro_rt->rt_gateway->sa_family == AF_LINK) {
+			struct sockaddr_in6 dest6;
+
+			bzero(&dest6, sizeof(dest6));
+			dest6.sin6_family = AF_INET6;
+			dest6.sin6_len = sizeof(dest6);
+			dest6.sin6_addr = ip6->ip6_dst;
+			ia6 = (struct in6_ifaddr *)
+			    ifa_ifwithaddr((struct sockaddr *)&dest6);
+			if (ia6 == NULL)
+				goto bad;
+			free_ia6 = 1;
+		}
+		else
+			ia6 = (struct in6_ifaddr *)rin6.ro_rt->rt_ifa;
 
 		/*
 		 * record address information into m_tag.
@@ -647,6 +666,8 @@ passin:
 			/* Count the packet in the ip address stats */
 			ia6->ia_ifa.if_ipackets++;
 			ia6->ia_ifa.if_ibytes += m->m_pkthdr.len;
+			if (ia6 != NULL && free_ia6 != 0)
+				ifa_free(&ia6->ia_ifa);
 			goto hbhcheck;
 		} else {
 			char ip6bufs[INET6_ADDRSTRLEN];
@@ -657,6 +678,8 @@ passin:
 			    ip6_sprintf(ip6bufs, &ip6->ip6_src),
 			    ip6_sprintf(ip6bufd, &ip6->ip6_dst)));
 
+			if (ia6 != NULL && free_ia6 != 0)
+				ifa_free(&ia6->ia_ifa);
 			goto bad;
 		}
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200908262132.n7QLWpMt075306>