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