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

Andrey V. Elsukov ae at FreeBSD.org
Tue Dec 17 10:03:06 UTC 2013


Author: ae
Date: Tue Dec 17 10:03:04 2013
New Revision: 259501
URL: http://svnweb.freebsd.org/changeset/base/259501

Log:
  Application can specify outgoing interface using setsockopt, this way
  affects all packets on the socket. This also called "sticky" options.
  And second way - specify the same options using ancillary data (using
  sendmsg(2)). This method overrides sticky options and affects only those
  datagrams, for which it was specified. Ancillary data can be used only
  with UDP and RAW sockets.
  
  Make sin6_scope_id check and initialization a bit later, when ancillary
  data is already parsed and we know specified outgoing interface.
  Also rename sa6_checkzone_pcb() function into sa6_checkzone_opts(), and
  use output options determined from sticky socket option or from ancillary
  data. Move sa6_checkzone_opts() declaration into ip6_var.h.
  
  Reported by:	melifaro
  Tested with:	rtadvd

Modified:
  user/ae/inet6/sys/netinet6/in6_pcb.c
  user/ae/inet6/sys/netinet6/ip6_var.h
  user/ae/inet6/sys/netinet6/raw_ip6.c
  user/ae/inet6/sys/netinet6/scope6.c
  user/ae/inet6/sys/netinet6/scope6_var.h
  user/ae/inet6/sys/netinet6/send.c
  user/ae/inet6/sys/netinet6/udp6_usrreq.c

Modified: user/ae/inet6/sys/netinet6/in6_pcb.c
==============================================================================
--- user/ae/inet6/sys/netinet6/in6_pcb.c	Tue Dec 17 09:22:25 2013	(r259500)
+++ user/ae/inet6/sys/netinet6/in6_pcb.c	Tue Dec 17 10:03:04 2013	(r259501)
@@ -138,7 +138,8 @@ in6_pcbbind(struct inpcb *inp, struct so
 		if (nam->sa_family != AF_INET6)
 			return (EAFNOSUPPORT);
 		/* Check sin6_scope_id. The caller must set it properly. */
-		if ((error = sa6_checkzone_pcb(inp, sin6)) != 0)
+		if ((error = sa6_checkzone_opts(inp->in6p_outputopts,
+		    inp->in6p_moptions, sin6)) != 0)
 			return (error);
 
 		if ((error = prison_local_ip6(cred, &sin6->sin6_addr,
@@ -323,7 +324,8 @@ in6_pcbconnect_mbuf(register struct inpc
 	/*
 	 * Check sin6_scope_id and automatically fill it, if possible.
 	 */
-	error = sa6_checkzone_pcb(inp, sin6);
+	error = sa6_checkzone_opts(inp->in6p_outputopts,
+	    inp->in6p_moptions, sin6);
 	if (error != 0)
 		return (error);
 	if ((error = prison_remote_ip6(inp->inp_cred, &sin6->sin6_addr)) != 0)

Modified: user/ae/inet6/sys/netinet6/ip6_var.h
==============================================================================
--- user/ae/inet6/sys/netinet6/ip6_var.h	Tue Dec 17 09:22:25 2013	(r259500)
+++ user/ae/inet6/sys/netinet6/ip6_var.h	Tue Dec 17 10:03:04 2013	(r259501)
@@ -398,6 +398,8 @@ int	ip6_setpktopts(struct mbuf *, struct
 void	ip6_clearpktopts(struct ip6_pktopts *, int);
 struct ip6_pktopts *ip6_copypktopts(struct ip6_pktopts *, int);
 int	ip6_optlen(struct inpcb *);
+int	sa6_checkzone_opts(struct ip6_pktopts *, struct ip6_moptions *,
+	struct sockaddr_in6 *);
 
 int	route6_input(struct mbuf **, int *, int);
 

Modified: user/ae/inet6/sys/netinet6/raw_ip6.c
==============================================================================
--- user/ae/inet6/sys/netinet6/raw_ip6.c	Tue Dec 17 09:22:25 2013	(r259500)
+++ user/ae/inet6/sys/netinet6/raw_ip6.c	Tue Dec 17 10:03:04 2013	(r259501)
@@ -430,6 +430,13 @@ rip6_output(struct mbuf *m, ...)
 		optp = in6p->in6p_outputopts;
 
 	/*
+	 * Application must provide a proper zone ID or the use of
+	 * default zone IDs should be enabled.
+	 */
+	error = sa6_checkzone_opts(optp, in6p->in6p_moptions, dstsock);
+	if (error != 0)
+		goto bad;
+	/*
 	 * For an ICMPv6 packet, we should know its type and code to update
 	 * statistics.
 	 */
@@ -738,7 +745,8 @@ rip6_bind(struct socket *so, struct sock
 	if (TAILQ_EMPTY(&V_ifnet) || addr->sin6_family != AF_INET6)
 		return (EADDRNOTAVAIL);
 	INP_RLOCK(inp);
-	error = sa6_checkzone_pcb(inp, addr);
+	error = sa6_checkzone_opts(inp->in6p_outputopts,
+	    inp->in6p_moptions, addr);
 	INP_RUNLOCK(inp);
 	if (error != 0)
 		return (error);
@@ -782,7 +790,8 @@ rip6_connect(struct socket *so, struct s
 	if (addr->sin6_family != AF_INET6)
 		return (EAFNOSUPPORT);
 	INP_RLOCK(inp);
-	error = sa6_checkzone_pcb(inp, addr);
+	error = sa6_checkzone_opts(inp->in6p_outputopts,
+	   inp->in6p_moptions, addr);
 	INP_RUNLOCK(inp);
 	if (error != 0)
 		return (error);
@@ -877,17 +886,6 @@ rip6_send(struct socket *so, int flags, 
 			m_freem(m);
 			return(EAFNOSUPPORT);
 		}
-		/*
-		 * Application must provide a proper zone ID or the use of
-		 * default zone IDs should be enabled.
-		 */
-		INP_RLOCK(inp);
-		ret = sa6_checkzone_pcb(inp, dst);
-		INP_RUNLOCK(inp);
-		if (ret != 0) {
-			m_freem(m);
-			return (ret);
-		}
 	}
 	ret = rip6_output(m, so, dst, control);
 	return (ret);

Modified: user/ae/inet6/sys/netinet6/scope6.c
==============================================================================
--- user/ae/inet6/sys/netinet6/scope6.c	Tue Dec 17 09:22:25 2013	(r259500)
+++ user/ae/inet6/sys/netinet6/scope6.c	Tue Dec 17 10:03:04 2013	(r259501)
@@ -521,7 +521,8 @@ sa6_checkzone_ifp(struct ifnet *ifp, str
 }
 
 int
-sa6_checkzone_pcb(struct inpcb *inp, struct sockaddr_in6 *sa6)
+sa6_checkzone_opts(struct ip6_pktopts *opts, struct ip6_moptions *mopts,
+    struct sockaddr_in6 *sa6)
 {
 	struct in6_pktinfo *pi;
 	int scope;
@@ -537,22 +538,39 @@ sa6_checkzone_pcb(struct inpcb *inp, str
 			 * socket options.
 			 * XXX: we will do this again in the in6_selectsrc().
 			 */
-			INP_LOCK_ASSERT(inp);
-			if (inp->in6p_outputopts != NULL) {
-				pi = inp->in6p_outputopts->ip6po_pktinfo;
+			/*
+			 * RFC 3542 p6.7:
+			 * If an interface is specified in an IPV6_PKTINFO
+			 * ancillary data item, the interface is used.
+			 */
+			if (opts != NULL) {
+				pi = opts->ip6po_pktinfo;
 				if (pi != NULL && pi->ipi6_ifindex != 0) {
 					/* XXX: in6_getscopezone */
 					sa6->sin6_scope_id = pi->ipi6_ifindex;
 					return (0);
 				}
 			}
-			if (inp->in6p_moptions != NULL &&
-			    inp->in6p_moptions->im6o_multicast_ifp != NULL) {
+			/*
+			 * If the destination address is a multicast
+			 * address and the IPV6_MULTICAST_IF socket option is
+			 * specified for the socket, the interface is used.
+			 */
+			if (mopts != NULL &&
+			    mopts->im6o_multicast_ifp != NULL) {
 				sa6->sin6_scope_id = in6_getscopezone(
-				    inp->in6p_moptions->im6o_multicast_ifp,
-				    scope);
+				    mopts->im6o_multicast_ifp, scope);
 				return (0);
 			}
+			/*
+			 * If an IPV6_NEXTHOP ancillary data item is
+			 * specified, the interface to the next hop is used.
+			 *
+			 * This option does not have any meaning for multicast
+			 * destinations. In such a case, the specified next hop
+			 * will be ignored.
+			 * XXX: handle IPV6_NEXTHOP
+			 */
 		}
 	}
 	return (sa6_checkzone(sa6));

Modified: user/ae/inet6/sys/netinet6/scope6_var.h
==============================================================================
--- user/ae/inet6/sys/netinet6/scope6_var.h	Tue Dec 17 09:22:25 2013	(r259500)
+++ user/ae/inet6/sys/netinet6/scope6_var.h	Tue Dec 17 10:03:04 2013	(r259501)
@@ -57,7 +57,6 @@ int	sa6_embedscope(struct sockaddr_in6 *
 int	sa6_recoverscope(struct sockaddr_in6 *);
 int	sa6_checkzone(struct sockaddr_in6 *);
 int	sa6_checkzone_ifp(struct ifnet *, struct sockaddr_in6 *);
-int	sa6_checkzone_pcb(struct inpcb *, struct sockaddr_in6 *);
 int	in6_setscope(struct in6_addr *, struct ifnet *, u_int32_t *);
 int	in6_clearscope(struct in6_addr *);
 uint16_t in6_getscope(struct in6_addr *);

Modified: user/ae/inet6/sys/netinet6/send.c
==============================================================================
--- user/ae/inet6/sys/netinet6/send.c	Tue Dec 17 09:22:25 2013	(r259500)
+++ user/ae/inet6/sys/netinet6/send.c	Tue Dec 17 10:03:04 2013	(r259501)
@@ -54,7 +54,6 @@ __FBSDID("$FreeBSD$");
 
 #include <netinet6/in6_var.h>
 #include <netinet6/nd6.h>
-#include <netinet6/scope6_var.h>
 #include <netinet6/send.h>
 
 static MALLOC_DEFINE(M_SEND, "send", "Secure Neighbour Discovery");

Modified: user/ae/inet6/sys/netinet6/udp6_usrreq.c
==============================================================================
--- user/ae/inet6/sys/netinet6/udp6_usrreq.c	Tue Dec 17 09:22:25 2013	(r259500)
+++ user/ae/inet6/sys/netinet6/udp6_usrreq.c	Tue Dec 17 10:03:04 2013	(r259501)
@@ -631,9 +631,6 @@ udp6_output(struct inpcb *inp, struct mb
 	INP_WLOCK_ASSERT(inp);
 	INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
 
-	bzero(&ro, sizeof(ro));
-	/* addr6 has been validated in udp6_send(). */
-	sin6 = (struct sockaddr_in6 *)addr6;
 	if (control) {
 		if ((error = ip6_setpktopts(control, &opt,
 		    inp->in6p_outputopts, td->td_ucred, IPPROTO_UDP)) != 0)
@@ -642,6 +639,18 @@ udp6_output(struct inpcb *inp, struct mb
 	} else
 		optp = inp->in6p_outputopts;
 
+	bzero(&ro, sizeof(ro));
+	if (addr6 != NULL) {
+		/*
+		 * Application must provide a proper zone ID or the use of
+		 * default zone IDs should be enabled.
+		 */
+		ro.ro_dst = *(struct sockaddr_in6 *)addr6;
+		sin6 = &ro.ro_dst;
+		error = sa6_checkzone_opts(optp, inp->in6p_moptions, sin6);
+		if (error != 0)
+			goto release;
+	}
 	if (sin6) {
 		faddr = &sin6->sin6_addr;
 
@@ -1075,7 +1084,6 @@ static int
 udp6_send(struct socket *so, int flags, struct mbuf *m,
     struct sockaddr *addr, struct mbuf *control, struct thread *td)
 {
-	struct sockaddr_in6 tmp;
 	struct inpcb *inp;
 	int error = 0;
 
@@ -1092,15 +1100,6 @@ udp6_send(struct socket *so, int flags, 
 			error = EAFNOSUPPORT;
 			goto bad;
 		}
-		/*
-		 * Application must provide a proper zone ID or the use of
-		 * default zone IDs should be enabled.
-		 */
-		tmp = *(struct sockaddr_in6 *)addr;
-		addr = (struct sockaddr *)&tmp;
-		error = sa6_checkzone_pcb(inp, &tmp);
-		if (error != 0)
-			goto bad;
 	}
 
 #ifdef INET


More information about the svn-src-user mailing list