svn commit: r246529 - user/ae/inet6/sys/netinet6

Andrey V. Elsukov ae at FreeBSD.org
Fri Feb 8 03:54:07 UTC 2013


Author: ae
Date: Fri Feb  8 03:54:06 2013
New Revision: 246529
URL: http://svnweb.freebsd.org/changeset/base/246529

Log:
  Rework ip6_setdstifaddr function. Keeping pointer to in6_ifaddr
  structure without holding the reference can lead to the panic.
  So, keep the destination address and zone id instead. Also rename
  it into ip6_savedstinfo(). ip6_getdstifaddr() function now uses
  saved address and zone id for in6_ifaddr lookup.
  Remove additional ia6 declarations, use already declared pointer.

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	Fri Feb  8 03:37:51 2013	(r246528)
+++ user/ae/inet6/sys/netinet6/ip6_input.c	Fri Feb  8 03:54:06 2013	(r246529)
@@ -147,7 +147,7 @@ struct rwlock in6_ifaddr_lock;
 RW_SYSINIT(in6_ifaddr_lock, &in6_ifaddr_lock, "in6_ifaddr_lock");
 
 static void ip6_init2(void *);
-static struct ip6aux *ip6_setdstifaddr(struct mbuf *, struct in6_ifaddr *);
+static struct ip6aux *ip6_savedstinfo(struct mbuf *, struct in6_addr *, uint32_t);
 static struct ip6aux *ip6_addaux(struct mbuf *);
 static struct ip6aux *ip6_findaux(struct mbuf *m);
 static void ip6_delaux (struct mbuf *);
@@ -428,6 +428,7 @@ ip6_input(struct mbuf *m)
 	int srcrt = 0;
 	struct llentry *lle = NULL;
 	struct sockaddr_in6 dst6, *dst;
+	struct ip6aux *aux;
 	int srcscope, dstscope;
 
 	bzero(&rin6, sizeof(struct route_in6));
@@ -446,6 +447,7 @@ ip6_input(struct mbuf *m)
 	/*
 	 * make sure we don't have onion peering information into m_tag.
 	 */
+	aux = NULL;
 	ip6_delaux(m);
 
 	if (m->m_flags & M_FASTFWD_OURS) {
@@ -707,10 +709,11 @@ passin:
 		/* 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);
 		ifa_free(&ia->ia_ifa);
 		deliverifp = m->m_pkthdr.rcvif;
+		/* record address information into m_tag. */
+		aux = ip6_savedstinfo(m, &ip6->ip6_dst,
+		    in6_getscopezone(deliverifp, dstscope));
 		ours = 1;
 		goto hbhcheck;
 	}
@@ -765,38 +768,34 @@ passin:
 #endif
 	    rin6.ro_rt->rt_ifp->if_type == IFT_LOOP) {
 		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) {
-			ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0);
-			if (ia6 == NULL)
+			ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
+			if (ia == NULL)
 				goto bad;
 			free_ia6 = 1;
 		}
 		else
-			ia6 = (struct in6_ifaddr *)rin6.ro_rt->rt_ifa;
-
-		/*
-		 * record address information into m_tag.
-		 */
-		(void)ip6_setdstifaddr(m, ia6);
+			ia = (struct in6_ifaddr *)rin6.ro_rt->rt_ifa;
 
 		/*
 		 * packets to a tentative, duplicated, or somehow invalid
 		 * address must not be accepted.
 		 */
-		if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) {
+		if (!(ia->ia6_flags & IN6_IFF_NOTREADY)) {
 			/* this address is ready */
 			ours = 1;
-			deliverifp = ia6->ia_ifp;	/* correct? */
+			deliverifp = ia->ia_ifp;	/* correct? */
 			/* Count the packet in the ip address stats */
-			ia6->ia_ifa.if_ipackets++;
-			ia6->ia_ifa.if_ibytes += m->m_pkthdr.len;
+			ia->ia_ifa.if_ipackets++;
+			ia->ia_ifa.if_ibytes += m->m_pkthdr.len;
+			/* record address information into m_tag. */
+			aux = ip6_savedstinfo(m, &ip6->ip6_dst,
+			    in6_getscopezone(deliverifp, dstscope));
 			if (free_ia6 != 0)
-				ifa_free(&ia6->ia_ifa);
+				ifa_free(&ia->ia_ifa);
 			goto hbhcheck;
 		} else {
 			char ip6bufs[INET6_ADDRSTRLEN];
@@ -807,8 +806,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);
+			if (free_ia6 != 0)
+				ifa_free(&ia->ia_ifa);
 			goto bad;
 		}
 	}
@@ -843,23 +842,20 @@ passin:
 	 * as our interface address (e.g. multicast addresses, addresses
 	 * within FAITH prefixes and such).
 	 */
-	if (deliverifp) {
-		struct in6_ifaddr *ia6;
-
- 		if ((ia6 = ip6_getdstifaddr(m)) != NULL) {
-			ifa_free(&ia6->ia_ifa);
-		} else {
-			ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst);
-			if (ia6) {
-				if (!ip6_setdstifaddr(m, ia6)) {
-					/*
-					 * XXX maybe we should drop the packet here,
-					 * as we could not provide enough information
-					 * to the upper layers.
-					 */
-				}
-				ifa_free(&ia6->ia_ifa);
+	if (deliverifp != NULL && aux == NULL) {
+		ia = in6_ifawithifp(deliverifp, &ip6->ip6_dst);
+		if (ia != NULL) {
+			dstscope = in6_addrscope(&ip6->ip6_dst);
+			aux = ip6_savedstinfo(m, &ip6->ip6_dst,
+			    in6_getscopezone(deliverifp, dstscope));
+			if (aux == NULL) {
+				/*
+				 * XXX maybe we should drop the packet here,
+				 * as we could not provide enough information
+				 * to the upper layers.
+				 */
 			}
+			ifa_free(&ia->ia_ifa);
 		}
 	}
 
@@ -1002,29 +998,28 @@ out:
  * we just bump the ia refcount when we receive it.  This should be fixed.
  */
 static struct ip6aux *
-ip6_setdstifaddr(struct mbuf *m, struct in6_ifaddr *ia6)
+ip6_savedstinfo(struct mbuf *m, struct in6_addr *addr, uint32_t zoneid)
 {
 	struct ip6aux *ip6a;
 
 	ip6a = ip6_addaux(m);
-	if (ip6a)
-		ip6a->ip6a_dstia6 = ia6;
-	return ip6a;	/* NULL if failed to set */
+	if (ip6a != NULL) {
+		ip6a->ip6a_dst = *addr;
+		ip6a->ip6a_dstzone = zoneid;
+	}
+	return (ip6a);	/* NULL if failed to set */
 }
 
 struct in6_ifaddr *
 ip6_getdstifaddr(struct mbuf *m)
 {
 	struct ip6aux *ip6a;
-	struct in6_ifaddr *ia;
 
 	ip6a = ip6_findaux(m);
-	if (ip6a) {
-		ia = ip6a->ip6a_dstia6;
-		ifa_ref(&ia->ia_ifa);
-		return ia;
-	} else
-		return NULL;
+	if (ip6a != NULL)
+		return (in6ifa_ifwithaddr(&ip6a->ip6a_dst,
+		    ip6a->ip6a_dstzone));
+	return (NULL);
 }
 
 /*


More information about the svn-src-user mailing list