summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/udp6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet6/udp6_output.c')
-rw-r--r--sys/netinet6/udp6_output.c67
1 files changed, 51 insertions, 16 deletions
diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c
index ee05019..fd4d6f3 100644
--- a/sys/netinet6/udp6_output.c
+++ b/sys/netinet6/udp6_output.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: udp6_output.c,v 1.14 2000/06/13 10:31:23 itojun Exp $ */
+/* $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -69,6 +69,7 @@
#include "opt_inet.h"
#include <sys/param.h>
+#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
@@ -120,22 +121,22 @@
int
udp6_output(in6p, m, addr6, control, p)
- register struct in6pcb *in6p;
- register struct mbuf *m;
+ struct in6pcb *in6p;
+ struct mbuf *m;
struct mbuf *control;
struct sockaddr *addr6;
struct proc *p;
{
- register u_int32_t ulen = m->m_pkthdr.len;
+ u_int32_t ulen = m->m_pkthdr.len;
u_int32_t plen = sizeof(struct udphdr) + ulen;
struct ip6_hdr *ip6;
struct udphdr *udp6;
- struct in6_addr *laddr, *faddr;
+ struct in6_addr *laddr, *faddr;
u_short fport;
int error = 0;
struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
int priv;
- int af, hlen;
+ int af = AF_INET6, hlen = sizeof(struct ip6_hdr);
int flags;
struct sockaddr_in6 tmp;
@@ -143,7 +144,7 @@ udp6_output(in6p, m, addr6, control, p)
if (p && !suser(p))
priv = 1;
if (control) {
- if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
+ if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0)
goto release;
in6p->in6p_outputopts = &opt;
}
@@ -164,6 +165,7 @@ udp6_output(in6p, m, addr6, control, p)
}
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
+ /* how about ::ffff:0.0.0.0 case? */
error = EISCONN;
goto release;
}
@@ -175,6 +177,24 @@ udp6_output(in6p, m, addr6, control, p)
faddr = &sin6->sin6_addr;
fport = sin6->sin6_port; /* allow 0 port */
+ if (IN6_IS_ADDR_V4MAPPED(faddr)) {
+ if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) {
+ /*
+ * I believe we should explicitly discard the
+ * packet when mapped addresses are disabled,
+ * rather than send the packet as an IPv6 one.
+ * If we chose the latter approach, the packet
+ * might be sent out on the wire based on the
+ * default route, the situation which we'd
+ * probably want to avoid.
+ * (20010421 jinmei@kame.net)
+ */
+ error = EINVAL;
+ goto release;
+ } else
+ af = AF_INET;
+ }
+
/* KAME hack: embed scopeid */
if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0) {
error = EINVAL;
@@ -187,7 +207,7 @@ udp6_output(in6p, m, addr6, control, p)
&in6p->in6p_route,
&in6p->in6p_laddr, &error);
} else
- laddr = &in6p->in6p_laddr; /*XXX*/
+ laddr = &in6p->in6p_laddr; /* XXX */
if (laddr == NULL) {
if (error == 0)
error = EADDRNOTAVAIL;
@@ -201,18 +221,29 @@ udp6_output(in6p, m, addr6, control, p)
error = ENOTCONN;
goto release;
}
+ if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) {
+ if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) {
+ /*
+ * XXX: this case would happen when the
+ * application sets the V6ONLY flag after
+ * connecting the foreign address.
+ * Such applications should be fixed,
+ * so we bark here.
+ */
+ log(LOG_INFO, "udp6_output: IPV6_V6ONLY "
+ "option was set for a connected socket\n");
+ error = EINVAL;
+ goto release;
+ } else
+ af = AF_INET;
+ }
laddr = &in6p->in6p_laddr;
faddr = &in6p->in6p_faddr;
fport = in6p->in6p_fport;
}
- if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
- af = AF_INET6;
- hlen = sizeof(struct ip6_hdr);
- } else {
- af = AF_INET;
+ if (af == AF_INET)
hlen = sizeof(struct ip);
- }
/*
* Calculate data length and get a mbuf
@@ -261,10 +292,13 @@ udp6_output(in6p, m, addr6, control, p)
udp6stat.udp6s_opackets++;
#ifdef IPSEC
- ipsec_setsocket(m, in6p->in6p_socket);
+ if (ipsec_setsocket(m, in6p->in6p_socket) != 0) {
+ error = ENOBUFS;
+ goto release;
+ }
#endif /*IPSEC*/
error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
- flags, in6p->in6p_moptions, NULL);
+ flags, in6p->in6p_moptions, NULL);
break;
case AF_INET:
error = EAFNOSUPPORT;
@@ -277,6 +311,7 @@ release:
releaseopt:
if (control) {
+ ip6_clearpktopts(in6p->in6p_outputopts, 0, -1);
in6p->in6p_outputopts = stickyopt;
m_freem(control);
}
OpenPOWER on IntegriCloud