summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>1999-12-21 09:00:53 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>1999-12-21 09:00:53 +0000
commit87852f3592239acfd199e6c63d2b1a76b6c9aa87 (patch)
treecc139212c64a78ae191055c94f1ebfee6b5b0ea9
parent99a148e6e138b480c510edaf5d955e521830eed4 (diff)
reuse encapsulate/decapsulate routine in ip_ip4.c from gif interface
(outer=IPv4 case). tested with (inner=IPv6, outer=IPv4) case. BUG ALERT: in_gif_output() assumes about ipe4_output()'s behavior too much. I mean, "tdb" is configured with certain knowledge about ipe4_output()'s behavior.
-rw-r--r--sys/netinet/in_gif.c235
-rw-r--r--sys/netinet/in_proto.c16
-rw-r--r--sys/netinet/ip_ip4.c188
3 files changed, 224 insertions, 215 deletions
diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c
index 15e2fcf716d..29452a4064a 100644
--- a/sys/netinet/in_gif.c
+++ b/sys/netinet/in_gif.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_gif.c,v 1.2 1999/12/09 03:45:21 angelos Exp $ */
+/* $OpenBSD: in_gif.c,v 1.3 1999/12/21 09:00:50 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -52,6 +52,7 @@
#include <netinet/ip_var.h>
#include <netinet/in_gif.h>
#include <netinet/ip_ecn.h>
+#include <netinet/ip_ipsp.h>
#ifdef INET6
#include <netinet/ip6.h>
@@ -75,6 +76,10 @@ int ip_gif_ttl = GIF_TTL;
int ip_gif_ttl = 0;
#endif
+#ifndef offsetof
+#define offsetof(s, e) ((int)&((s *)0)->e)
+#endif
+
int
in_gif_output(ifp, family, m, rt)
struct ifnet *ifp;
@@ -83,12 +88,13 @@ in_gif_output(ifp, family, m, rt)
struct rtentry *rt;
{
register struct gif_softc *sc = (struct gif_softc*)ifp;
- struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst;
struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc;
struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst;
- struct ip iphdr; /* capsule IP header, host byte ordered */
- int proto;
- u_int8_t tos;
+ struct tdb tdb;
+ struct xformsw xfs;
+ int error;
+ int hlen, poff;
+ struct mbuf *mp;
if (sin_src == NULL || sin_dst == NULL ||
sin_src->sin_family != AF_INET ||
@@ -97,125 +103,68 @@ in_gif_output(ifp, family, m, rt)
return EAFNOSUPPORT;
}
+ /* multi-destination mode is not supported */
+ if (ifp->if_flags & IFF_LINK0) {
+ m_freem(m);
+ return ENETUNREACH;
+ }
+
+ /* setup dummy tdb. it highly depends on ipe4_output() code. */
+ memset(&tdb, 0, sizeof(tdb));
+ memset(&xfs, 0, sizeof(xfs));
+ tdb.tdb_src.sin.sin_family = AF_INET;
+ tdb.tdb_src.sin.sin_len = sizeof(struct sockaddr_in);
+ tdb.tdb_src.sin.sin_addr = sin_src->sin_addr;
+ tdb.tdb_dst.sin.sin_family = AF_INET;
+ tdb.tdb_dst.sin.sin_len = sizeof(struct sockaddr_in);
+ tdb.tdb_dst.sin.sin_addr = sin_dst->sin_addr;
+ tdb.tdb_xform = &xfs;
+ xfs.xf_type = -1; /* not XF_IP4 */
+
switch (family) {
-#ifdef INET
case AF_INET:
- {
- struct ip *ip;
-
- proto = IPPROTO_IPV4;
- if (m->m_len < sizeof(*ip)) {
- m = m_pullup(m, sizeof(*ip));
- if (!m)
+ if (m->m_len < sizeof(struct ip)) {
+ m = m_pullup(m, sizeof(struct ip));
+ if (m == NULL)
return ENOBUFS;
}
- ip = mtod(m, struct ip *);
- tos = ip->ip_tos;
+ hlen = (mtod(m, struct ip *)->ip_hl) << 2;
+ poff = offsetof(struct ip, ip_p);
break;
- }
-#endif /*INET*/
#ifdef INET6
case AF_INET6:
- {
- struct ip6_hdr *ip6;
- proto = IPPROTO_IPV6;
- if (m->m_len < sizeof(*ip6)) {
- m = m_pullup(m, sizeof(*ip6));
- if (!m)
- return ENOBUFS;
- }
- ip6 = mtod(m, struct ip6_hdr *);
- tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
+ hlen = sizeof(struct ip6_hdr);
+ poff = offsetof(struct ip6_hdr, ip6_nxt);
break;
- }
-#endif /*INET6*/
- default:
-#ifdef DIAGNOSTIC
- printf("in_gif_output: warning: unknown family %d passed\n",
- family);
#endif
+ default:
m_freem(m);
return EAFNOSUPPORT;
}
- bzero(&iphdr, sizeof(iphdr));
- iphdr.ip_src = sin_src->sin_addr;
- if (ifp->if_flags & IFF_LINK0) {
- /* multi-destination mode */
- if (sin_dst->sin_addr.s_addr != INADDR_ANY)
- iphdr.ip_dst = sin_dst->sin_addr;
- else if (rt) {
- if (family != AF_INET) {
- m_freem(m);
- return EINVAL; /*XXX*/
- }
- iphdr.ip_dst = ((struct sockaddr_in *)
- (rt->rt_gateway))->sin_addr;
- } else {
- m_freem(m);
- return ENETUNREACH;
- }
- } else {
- /* bidirectional configured tunnel mode */
- if (sin_dst->sin_addr.s_addr != INADDR_ANY)
- iphdr.ip_dst = sin_dst->sin_addr;
- else {
- m_freem(m);
- return ENETUNREACH;
- }
- }
- iphdr.ip_p = proto;
- /* version will be set in ip_output() */
- iphdr.ip_ttl = ip_gif_ttl;
- iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip);
- if (ifp->if_flags & IFF_LINK1)
- ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos);
-
- /* prepend new IP header */
- M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
- if (m && m->m_len < sizeof(struct ip))
- m = m_pullup(m, sizeof(struct ip));
- if (m == NULL) {
- printf("ENOBUFS in in_gif_output %d\n", __LINE__);
- return ENOBUFS;
- }
+ /* encapsulate into IPv4 packet */
+ mp = NULL;
+ error = ipe4_output(m, &tdb, &mp, hlen, poff);
+ if (error)
+ return error;
+ else if (mp == NULL)
+ return EFAULT;
- *(mtod(m, struct ip *)) = iphdr;
-
- if (dst->sin_family != sin_dst->sin_family ||
- dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
- /* cache route doesn't match */
- dst->sin_family = sin_dst->sin_family;
- dst->sin_len = sizeof(struct sockaddr_in);
- dst->sin_addr = sin_dst->sin_addr;
- if (sc->gif_ro.ro_rt) {
- RTFREE(sc->gif_ro.ro_rt);
- sc->gif_ro.ro_rt = NULL;
- }
-#if 0
- sc->gif_if.if_mtu = GIF_MTU;
-#endif
- }
+ m = mp;
- if (sc->gif_ro.ro_rt == NULL) {
- rtalloc(&sc->gif_ro);
- if (sc->gif_ro.ro_rt == NULL) {
- m_freem(m);
- return ENETUNREACH;
- }
-#if 0
- ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu
- - sizeof(struct ip);
-#endif
+ {
+ /* ip_output needs host-order length. it should be nuked */
+ struct ip *ip;
+ if (m->m_len < sizeof(struct ip)) {
+ m = m_pullup(m, sizeof(struct ip));
+ if (m == NULL)
+ return ENOBUFS;
}
-
-#ifdef IPSEC
-#ifndef __OpenBSD__ /*KAME IPSEC*/
- m->m_pkthdr.rcvif = NULL;
-#endif
-#endif /*IPSEC*/
+ ip = mtod(m, struct ip *);
+ ip->ip_len = ntohs(ip->ip_len);
+ }
- return ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL);
+ return ip_output(m, NULL, NULL, 0, NULL, NULL);
}
void
@@ -231,15 +180,21 @@ in_gif_input(m, va_alist)
struct gif_softc *sc;
struct ifnet *gifp = NULL;
struct ip *ip;
- int i, af;
+ int i;
va_list ap;
- u_int8_t otos;
va_start(ap, m);
off = va_arg(ap, int);
proto = va_arg(ap, int);
va_end(ap);
+ /*
+ * XXX
+ * what if we run transport-mode IPsec to protect gif tunnel?
+ */
+ if (m->m_flags & (M_AUTH | M_CONF))
+ goto inject;
+
ip = mtod(m, struct ip *);
/* this code will be soon improved. */
@@ -270,64 +225,10 @@ in_gif_input(m, va_alist)
}
}
- if (gifp == NULL) {
-#ifdef MROUTING
- /* for backward compatibility */
- if (proto == IPPROTO_IPV4) {
- ipip_input(m, off, proto);
- return;
- }
-#endif /*MROUTING*/
- m_freem(m);
- ipstat.ips_nogif++;
- return;
- }
+ if (gifp && (m->m_flags & (M_AUTH | M_CONF)) == 0)
+ m->m_pkthdr.rcvif = gifp;
- otos = ip->ip_tos;
- m_adj(m, off);
-
- switch (proto) {
-#ifdef INET
- case IPPROTO_IPV4:
- {
- struct ip *ip;
- af = AF_INET;
- if (m->m_len < sizeof(*ip)) {
- m = m_pullup(m, sizeof(*ip));
- if (!m)
- return;
- }
- ip = mtod(m, struct ip *);
- if (gifp->if_flags & IFF_LINK1)
- ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos);
- break;
- }
-#endif
-#ifdef INET6
- case IPPROTO_IPV6:
- {
- struct ip6_hdr *ip6;
- u_int8_t itos;
- af = AF_INET6;
- if (m->m_len < sizeof(*ip6)) {
- m = m_pullup(m, sizeof(*ip6));
- if (!m)
- return;
- }
- ip6 = mtod(m, struct ip6_hdr *);
- itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
- if (gifp->if_flags & IFF_LINK1)
- ip_ecn_egress(ECN_ALLOWED, &otos, &itos);
- ip6->ip6_flow &= ~htonl(0xff << 20);
- ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
- break;
- }
-#endif /* INET6 */
- default:
- ipstat.ips_nogif++;
- m_freem(m);
- return;
- }
- gif_input(m, af, gifp);
+inject:
+ ip4_input(m, off, proto);
return;
}
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index e380f34a094..4260265267a 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_proto.c,v 1.17 1999/12/09 03:46:59 angelos Exp $ */
+/* $OpenBSD: in_proto.c,v 1.18 1999/12/21 09:00:52 itojun Exp $ */
/* $NetBSD: in_proto.c,v 1.14 1996/02/18 18:58:32 christos Exp $ */
/*
@@ -196,11 +196,11 @@ struct protosw inetsw[] = {
rip_usrreq,
0, 0, 0, 0, icmp_sysctl
},
-#if NGIF > 0 && !defined(IPSEC)
+#if NGIF > 0
{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR,
- in_gif_input, 0, 0, 0,
+ in_gif_input, rip_output, 0, rip_ctloutput,
0,
- 0, 0, 0, 0,
+ 0, 0, 0, 0, ip4_sysctl
},
#ifdef INET6
{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR,
@@ -210,20 +210,18 @@ struct protosw inetsw[] = {
},
#endif /* INET6 */
#else /* NGIF */
-#if defined(IPSEC) || defined(MROUTING)
{ SOCK_RAW, &inetdomain, IPPROTO_IPIP, PR_ATOMIC|PR_ADDR,
ip4_input, rip_output, 0, rip_ctloutput,
rip_usrreq, /* XXX */
0, 0, 0, 0, ip4_sysctl
},
-#if NGIF > 0 && defined(INET6)
+#ifdef INET6
{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR,
- in_gif_input, 0, 0, 0,
+ ip4_input, rip_output, 0, rip_ctloutput,
0,
0, 0, 0, 0,
},
-#endif /* NGIF && INET6 */
-#endif /* MROUTING || IPSEC */
+#endif /* INET6 */
#endif /*NGIF*/
{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR,
igmp_input, rip_output, 0, rip_ctloutput,
diff --git a/sys/netinet/ip_ip4.c b/sys/netinet/ip_ip4.c
index c9b831e963a..19d074ad781 100644
--- a/sys/netinet/ip_ip4.c
+++ b/sys/netinet/ip_ip4.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ip4.c,v 1.41 1999/12/09 20:38:35 angelos Exp $ */
+/* $OpenBSD: ip_ip4.c,v 1.42 1999/12/21 09:00:52 itojun Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -116,8 +116,17 @@ ip4_input(m, va_alist)
register struct ifaddr *ifa;
struct ifqueue *ifq = NULL;
struct ip *ipo;
+#ifdef INET6
+ register struct sockaddr_in6 *sin6;
+ struct ip6_hdr *ip6 = NULL;
+#endif
+ u_int8_t nxt;
int s, iphlen;
va_list ap;
+ int isr;
+ u_int8_t otos, itos;
+ u_int8_t v;
+ int hlen;
va_start(ap, m);
iphlen = va_arg(ap, int);
@@ -125,7 +134,6 @@ ip4_input(m, va_alist)
ip4stat.ip4s_ipackets++;
-#ifdef MROUTING
/* Bring the IP(v4) header in the first mbuf, if not there already */
if (m->m_len < sizeof(struct ip))
{
@@ -140,7 +148,8 @@ ip4_input(m, va_alist)
ipo = mtod(m, struct ip *);
- if (ipo->ip_v == IPVERSION)
+#ifdef MROUTING
+ if (ipo->ip_v == IPVERSION && ipo->ip_p == IPPROTO_IPV4)
{
if (IN_MULTICAST(((struct ip *)((char *)ipo + iphlen))->ip_dst.s_addr))
{
@@ -150,6 +159,9 @@ ip4_input(m, va_alist)
}
#endif MROUTING
+ /* keep outer ecn field */
+ otos = ipo->ip_tos;
+
/* If we do not accept IP4 explicitly, drop. */
if (!ip4_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0)
{
@@ -162,10 +174,22 @@ ip4_input(m, va_alist)
/* Remove outter IP header */
m_adj(m, iphlen);
+ m_copydata(m, 0, 1, &v);
+ if ((v >> 4) == 4)
+ hlen = sizeof(struct ip);
+#ifdef INET6
+ else if ((v >> 4) == 6)
+ hlen = sizeof(struct ip6_hdr);
+#endif
+ else {
+ m_freem(m);
+ return /*EAFNOSUPPORT*/;
+ }
+
/* Bring the inner IP(v4) header in the first mbuf, if not there already */
- if (m->m_len < sizeof(struct ip))
+ if (m->m_len < hlen)
{
- if ((m = m_pullup(m, sizeof(struct ip))) == 0)
+ if ((m = m_pullup(m, hlen)) == 0)
{
DPRINTF(("ip4_input(): m_pullup() failed\n"));
ip4stat.ip4s_hdrops++;
@@ -174,6 +198,7 @@ ip4_input(m, va_alist)
}
ipo = mtod(m, struct ip *);
+ v = ipo->ip_v;
/*
* RFC 1853 specifies that the inner TTL should not be touched on
@@ -182,8 +207,18 @@ ip4_input(m, va_alist)
*/
/* Some sanity checks in the inner IPv4 header */
- if (ipo->ip_v != IPVERSION)
- {
+ switch (v) {
+ case IPVERSION:
+ nxt = ipo->ip_p;
+ break;
+#ifdef INET6
+ case 6:
+ ip6 = (struct ip6_hdr *)ipo;
+ ipo = NULL;
+ nxt = ip6->ip6_nxt;
+ break;
+#endif
+ default:
DPRINTF(("ip4_input(): wrong version %d on packet from %s to %s (%s->%s)\n", ipo->ip_v, inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst), inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst)));
ip4stat.ip4s_family++;
m_freem(m);
@@ -195,8 +230,7 @@ ip4_input(m, va_alist)
* not accept a packet with double ip4 headers neither.
*/
- if (!ip4_allow && ((ipo->ip_p == IPPROTO_IPIP) ||
- (ipo->ip_p == IPPROTO_IPV6)))
+ if (!ip4_allow && ((nxt == IPPROTO_IPIP) || (nxt == IPPROTO_IPV6)))
{
DPRINTF(("ip4_input(): dropped due to policy\n"));
ip4stat.ip4s_pdrops++;
@@ -204,32 +238,68 @@ ip4_input(m, va_alist)
return;
}
+ /* update inner ecn field. */
+ switch (v) {
+ case IPVERSION:
+ ip_ecn_egress(ECN_ALLOWED, &otos, &ipo->ip_tos);
+ break;
+#ifdef INET6
+ case 6:
+ itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
+ ip_ecn_egress(ECN_ALLOWED, &otos, &itos);
+ ip6->ip6_flow &= ~htonl(0xff << 20);
+ ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
+ break;
+#endif
+ }
+
/* Check for local address spoofing. */
if (m->m_pkthdr.rcvif == NULL ||
!(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK))
{
for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next)
- for (ifa = ifp->if_addrlist.tqh_first;
- ifa != 0;
- ifa = ifa->ifa_list.tqe_next)
- {
- if (ifa->ifa_addr->sa_family != AF_INET)
- continue;
-
- sin = (struct sockaddr_in *) ifa->ifa_addr;
-
- if (sin->sin_addr.s_addr == ipo->ip_src.s_addr)
- {
- DPRINTF(("ip_input(): possible local address spoofing detected on packet from %s to %s (%s->%s)\n", inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst), inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst)));
- ip4stat.ip4s_spoof++;
- m_freem(m);
- return;
- }
- }
+ {
+ for (ifa = ifp->if_addrlist.tqh_first;
+ ifa != 0;
+ ifa = ifa->ifa_list.tqe_next)
+ {
+ if (ipo)
+ {
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+
+ sin = (struct sockaddr_in *) ifa->ifa_addr;
+
+ if (sin->sin_addr.s_addr == ipo->ip_src.s_addr)
+ {
+ DPRINTF(("ip4_input(): possible local address spoofing detected on packet from %s to %s (%s->%s)\n", inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst), inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst)));
+ ip4stat.ip4s_spoof++;
+ m_freem(m);
+ return;
+ }
+ }
+ else if (ip6)
+ {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+
+ sin6 = (struct sockaddr_in6 *) ifa->ifa_addr;
+
+ if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_src))
+ {
+ DPRINTF(("ip4_input(): possible local address spoofing detected on packet\n"));
+ m_freem(m);
+ return;
+ }
+
+ }
+ }
+ }
}
/* Statistics */
- ip4stat.ip4s_ibytes += m->m_pkthdr.len - iphlen;
+ if (ipo)
+ ip4stat.ip4s_ibytes += m->m_pkthdr.len - iphlen;
/* tdbi is only set in ESP or AH, if the next protocol is UDP or TCP */
if (m->m_flags & (M_CONF|M_AUTH))
@@ -243,14 +313,31 @@ ip4_input(m, va_alist)
* untrusted packets.
*/
- ifq = &ipintrq;
+ if (ipo)
+ {
+ ifq = &ipintrq;
+ isr = NETISR_IP;
+ }
+ else if (ip6)
+ {
+ ifq = &ip6intrq;
+ isr = NETISR_IPV6;
+ }
+ else
+ {
+ /* just in case */
+ m_freem(m);
+ return;
+ }
s = splimp(); /* isn't it already? */
if (IF_QFULL(ifq))
{
IF_DROP(ifq);
m_freem(m);
- ip4stat.ip4s_qfull++;
+ if (ipo)
+ ip4stat.ip4s_qfull++;
+
splx(s);
DPRINTF(("ip4_input(): packet dropped because of full queue\n"));
@@ -258,7 +345,7 @@ ip4_input(m, va_alist)
}
IF_ENQUEUE(ifq, m);
- schednetisr(NETISR_IP);
+ schednetisr(isr);
splx(s);
return;
@@ -296,6 +383,8 @@ ipe4_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
{
DPRINTF(("ipe4_output(): unspecified tunnel endpoind address in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
ip4stat.ip4s_unspec++;
+ m_freem(m);
+ *mp = NULL;
return ENOBUFS;
}
@@ -304,6 +393,7 @@ ipe4_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
{
DPRINTF(("ipe4_output(): M_PREPEND failed\n"));
ip4stat.ip4s_hdrops++;
+ *mp = NULL;
return ENOBUFS;
}
@@ -340,21 +430,28 @@ ipe4_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
sizeof(u_int16_t), (caddr_t) &ipo->ip_off);
ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK);
}
-
#ifdef INET6
- if (tp == IPPROTO_IPV6)
+ else if (tp == (IPV6_VERSION >> 4))
{
+ u_int32_t itos32;
/* Save ECN notification */
m_copydata(m, sizeof(struct ip) +
offsetof(struct ip6_hdr, ip6_flow),
- sizeof(u_int32_t), (caddr_t) &itos);
- itos = ntohl(itos) >> 20;
+ sizeof(u_int32_t), (caddr_t) &itos32);
+ itos = ntohl(itos32) >> 20;
ipo->ip_p = IPPROTO_IPV6;
ipo->ip_off = 0;
}
#endif /* INET6 */
+ else
+ {
+ m_freem(m);
+ *mp = NULL;
+ return EAFNOSUPPORT;
+ }
+ otos = 0;
ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
ipo->ip_tos = otos;
break;
@@ -368,6 +465,8 @@ ipe4_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
{
DPRINTF(("ipe4_output(): unspecified tunnel endpoind address in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
ip4stat.ip4s_unspec++;
+ m_freem(m);
+ *mp = NULL;
return ENOBUFS;
}
@@ -376,13 +475,15 @@ ipe4_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
{
DPRINTF(("ipe4_output(): M_PREPEND failed\n"));
ip4stat.ip4s_hdrops++;
+ *mp = NULL;
return ENOBUFS;
}
/* Initialize IPv6 header */
ip6o = mtod(m, struct ip6_hdr *);
ip6o->ip6_flow = 0;
- ip6o->ip6_vfc = IPV6_VERSION;
+ ip6o->ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6o->ip6_vfc |= IPV6_VERSION;
ip6o->ip6_plen = htons(m->m_pkthdr.len);
ip6o->ip6_hlim = ip_defttl;
ip6o->ip6_dst = tdb->tdb_dst.sin6.sin6_addr;
@@ -398,19 +499,27 @@ ipe4_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
ip6o->ip6_nxt = IPPROTO_IPIP; /* This is really IPVERSION */
}
+ else
#endif /* INET */
-
- if (tp == IPPROTO_IPV6)
+ if (tp == (IPV6_VERSION >> 4))
{
+ u_int32_t itos32;
/* Save ECN notification */
m_copydata(m, sizeof(struct ip6_hdr) +
offsetof(struct ip6_hdr, ip6_flow),
- sizeof(u_int32_t), (caddr_t) &itos);
- itos = ntohl(itos) >> 20;
+ sizeof(u_int32_t), (caddr_t) &itos32);
+ itos = ntohl(itos32) >> 20;
ip6o->ip6_nxt = IPPROTO_IPV6;
}
+ else
+ {
+ m_freem(m);
+ *mp = NULL;
+ return EAFNOSUPPORT;
+ }
+ otos = 0;
ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
ip6o->ip6_flow |= htonl((u_int32_t) otos << 20);
break;
@@ -420,6 +529,7 @@ ipe4_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
DPRINTF(("ipe4_output(): unsupported protocol family %d\n",
tdb->tdb_dst.sa.sa_family));
m_freem(m);
+ *mp = NULL;
ip4stat.ip4s_family++;
return ENOBUFS;
}