Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 7 Feb 2013 16:39:37 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r246489 - user/ae/inet6/sys/netinet6
Message-ID:  <201302071639.r17Gdb7Z023211@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Thu Feb  7 16:39:36 2013
New Revision: 246489
URL: http://svnweb.freebsd.org/changeset/base/246489

Log:
  Rework the unicast check. Use in6_addrscope to determine the scope of
  source and destination addresses. If source address is from the
  link-local scope, then check that it is loopback. If so, then it must
  be received on the loopback interface. Based on the receiving interface
  and destination address scope, determine the corresponding ifaddr.
  If destination address has link-local scope and ifaddr wasn't found,
  this means that the address is from the different zone.

Modified:
  user/ae/inet6/sys/netinet6/ip6_input.c

Modified: user/ae/inet6/sys/netinet6/ip6_input.c
==============================================================================
--- user/ae/inet6/sys/netinet6/ip6_input.c	Thu Feb  7 15:49:05 2013	(r246488)
+++ user/ae/inet6/sys/netinet6/ip6_input.c	Thu Feb  7 16:39:36 2013	(r246489)
@@ -424,9 +424,11 @@ ip6_input(struct mbuf *m)
 	struct ifnet *deliverifp = NULL, *ifp = NULL;
 	struct in6_addr odst;
 	struct route_in6 rin6;
+	struct in6_ifaddr *ia;
 	int srcrt = 0;
 	struct llentry *lle = NULL;
 	struct sockaddr_in6 dst6, *dst;
+	int srcscope, dstscope;
 
 	bzero(&rin6, sizeof(struct route_in6));
 #ifdef IPSEC
@@ -661,64 +663,37 @@ passin:
 		deliverifp = m->m_pkthdr.rcvif;
 		goto hbhcheck;
 	}
-
-	/*
-	 * Disambiguate address scope zones (if there is ambiguity).
-	 * in6_setscope() then also checks and rejects the cases where src or
-	 * dst are the loopback address and the receiving interface
-	 * is not loopback.
-	 */
-	if (in6_setscope(&ip6->ip6_src, m->m_pkthdr.rcvif, NULL) ||
-	    in6_setscope(&ip6->ip6_dst, m->m_pkthdr.rcvif, NULL)) {
-		V_ip6stat.ip6s_badscope++;
-		goto bad;
-	}
-
 	/*
 	 *  Unicast check
 	 */
-
-	bzero(&dst6, sizeof(dst6));
-	dst6.sin6_family = AF_INET6;
-	dst6.sin6_len = sizeof(struct sockaddr_in6);
-	dst6.sin6_addr = ip6->ip6_dst;
-	ifp = m->m_pkthdr.rcvif;
-	IF_AFDATA_RLOCK(ifp);
-	lle = lla_lookup(LLTABLE6(ifp), 0,
-	     (struct sockaddr *)&dst6);
-	IF_AFDATA_RUNLOCK(ifp);
-	if ((lle != NULL) && (lle->la_flags & LLE_IFADDR)) {
-		struct ifaddr *ifa;
-		struct in6_ifaddr *ia6;
-		int bad;
-
-		bad = 1;
-#define	sa_equal(a1, a2)						\
-	(bcmp((a1), (a2), ((a1))->sin6_len) == 0)
-		IF_ADDR_RLOCK(ifp);
-		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
-			if (ifa->ifa_addr->sa_family != dst6.sin6_family)
-				continue;
-			if (sa_equal(&dst6, ifa->ifa_addr))
-				break;
+	srcscope = in6_addrscope(&ip6->ip6_src);
+	dstscope = in6_addrscope(&ip6->ip6_dst);
+	if (srcscope == IPV6_ADDR_SCOPE_LINKLOCAL &&
+	    IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
+		/*
+		 * Packets with the loopback source address must be
+		 * received on the loopback interface.
+		 */
+		if (m->m_pkthdr.rcvif != V_loif) {
+			V_ip6stat.ip6s_badscope++;
+			goto bad;
 		}
-		KASSERT(ifa != NULL, ("%s: ifa not found for lle %p",
-		    __func__, lle));
-#undef sa_equal
-
-		ia6 = (struct in6_ifaddr *)ifa;
-		if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) {
-			/* Count the packet in the ip address stats */
-			ia6->ia_ifa.if_ipackets++;
-			ia6->ia_ifa.if_ibytes += m->m_pkthdr.len;
-
-			/*
-			 * record address information into m_tag.
-			 */
-			(void)ip6_setdstifaddr(m, ia6);
-
-			bad = 0;
-		} else {
+	}
+	ia = in6ifa_ifwithaddr(&ip6->ip6_dst,
+	    in6_getscopezone(m->m_pkthdr.rcvif, dstscope));
+	if (ia == NULL) {
+	       if (dstscope == IPV6_ADDR_SCOPE_LINKLOCAL) {
+		       /*
+			* This means that the receiving interface doesn't
+			* have this link-local address configured.
+			* This also covers the loopback destination address.
+			*/
+		       V_ip6stat.ip6s_badscope++;
+		       goto bad;
+	       }
+	       /* FALLTHROUGH */
+	} else {
+		if (ia->ia6_flags & IN6_IFF_NOTREADY) {
 			char ip6bufs[INET6_ADDRSTRLEN];
 			char ip6bufd[INET6_ADDRSTRLEN];
 			/* address is not ready, so discard the packet. */
@@ -726,19 +701,17 @@ passin:
 			    "ip6_input: packet to an unready address %s->%s\n",
 			    ip6_sprintf(ip6bufs, &ip6->ip6_src),
 			    ip6_sprintf(ip6bufd, &ip6->ip6_dst)));
-		}
-		IF_ADDR_RUNLOCK(ifp);
-		LLE_RUNLOCK(lle);
-		if (bad)
 			goto bad;
-		else {
-			ours = 1;
-			deliverifp = ifp;
-			goto hbhcheck;
 		}
+		/* Count the packet in the ip address stats */
+		ia->ia_ifa.if_ipackets++;
+		ia->ia_ifa.if_ibytes += m->m_pkthdr.len;
+		/* record address information into m_tag. */
+		ip6_setdstifaddr(m, ia);
+		deliverifp = m->m_pkthdr.rcvif;
+		ours = 1;
+		goto hbhcheck;
 	}
-	if (lle != NULL)
-		LLE_RUNLOCK(lle);
 
 	dst = &rin6.ro_dst;
 	dst->sin6_len = sizeof(struct sockaddr_in6);



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