summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2010-05-11 09:36:08 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2010-05-11 09:36:08 +0000
commit62fc95fd847703423c4902b3205c6d9517f20006 (patch)
tree7d05c62bdb72350f0f01022800ac767f57e999a4
parent1b7752fdde26fac73c4c3bb416b412ce523cc945 (diff)
Massiv cleanup of the gif(4) mess. Move encapsulation into gif_output()
where it is not necessary to guess protocols by looking at the first nibble. in_gif_output() will encapsulate the packet but not send it. Because of etherip support and the way the bridge works a minimal hack is needed in gif_start() to ensure that the bridged packets are encapsulated as well. This actually started with the idea to add MPLS support but that turned out to be not as simple as in the gre(4) case. Tested by myself (IP, IPv6, etherip, MPLS), sthen@ (IP, IPv6), naddy (IPv6) OK sthen@
-rw-r--r--sys/net/if_gif.c229
-rw-r--r--sys/netinet/in_gif.c38
-rw-r--r--sys/netinet/in_gif.h4
-rw-r--r--sys/netinet/in_proto.c23
-rw-r--r--sys/netinet/ip_ether.c362
-rw-r--r--sys/netinet/ip_ether.h7
-rw-r--r--sys/netinet/ip_ipip.c87
-rw-r--r--sys/netinet/ip_ipsp.h9
-rw-r--r--sys/netinet6/in6_gif.c72
-rw-r--r--sys/netinet6/in6_gif.h4
10 files changed, 536 insertions, 299 deletions
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index e6a28b87d5f..cb9ccba73e0 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_gif.c,v 1.53 2009/11/22 12:33:25 deraadt Exp $ */
+/* $OpenBSD: if_gif.c,v 1.54 2010/05/11 09:36:07 claudio Exp $ */
/* $KAME: if_gif.c,v 1.43 2001/02/20 08:51:07 itojun Exp $ */
/*
@@ -49,6 +49,7 @@
#include <netinet/in_var.h>
#include <netinet/in_gif.h>
#include <netinet/ip.h>
+#include <netinet/ip_var.h>
#endif /* INET */
#ifdef INET6
@@ -56,6 +57,7 @@
#include <netinet/in.h>
#endif
#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
#include <netinet6/in6_gif.h>
#endif /* INET6 */
@@ -67,6 +69,7 @@
void gifattach(int);
int gif_clone_create(struct if_clone *, int);
int gif_clone_destroy(struct ifnet *);
+int gif_checkloop(struct ifnet *, struct mbuf *);
/*
* gif global variable definitions
@@ -145,24 +148,8 @@ gif_start(struct ifnet *ifp)
{
struct gif_softc *sc = (struct gif_softc*)ifp;
struct mbuf *m;
- struct m_tag *mtag;
- int family;
int s;
- u_int8_t tp;
-
- /* is interface up and running? */
- if ((ifp->if_flags & (IFF_OACTIVE | IFF_UP)) != IFF_UP ||
- sc->gif_psrc == NULL || sc->gif_pdst == NULL)
- return;
-
- /* are the tunnel endpoints valid? */
-#ifdef INET
- if (sc->gif_psrc->sa_family != AF_INET)
-#endif
-#ifdef INET6
- if (sc->gif_psrc->sa_family != AF_INET6)
-#endif
- return;
+ sa_family_t family;
while (1) {
s = splnet();
@@ -172,77 +159,124 @@ gif_start(struct ifnet *ifp)
if (m == NULL)
break;
- /*
- * gif may cause infinite recursion calls when misconfigured.
- * We'll prevent this by detecting loops.
- */
- for (mtag = m_tag_find(m, PACKET_TAG_GIF, NULL); mtag;
- mtag = m_tag_find(m, PACKET_TAG_GIF, mtag)) {
- if (!bcmp((caddr_t)(mtag + 1), &ifp,
- sizeof(struct ifnet *))) {
- IF_DROP(&ifp->if_snd);
- log(LOG_NOTICE, "gif_output: "
- "recursively called too many times\n");
- m_freem(m);
- break;
- }
- }
- if (mtag)
- continue;
-
- mtag = m_tag_get(PACKET_TAG_GIF, sizeof(caddr_t), M_NOWAIT);
- if (mtag == NULL) {
+ /* is interface up and usable? */
+ if ((ifp->if_flags & (IFF_OACTIVE | IFF_UP)) != IFF_UP ||
+ sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
+ sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) {
m_freem(m);
- break;
+ continue;
}
- bcopy(&ifp, mtag + 1, sizeof(caddr_t));
- m_tag_prepend(m, mtag);
+
+ /* get tunnel address family */
+ family = sc->gif_psrc->sa_family;
/*
- * Remove multicast and broadcast flags or encapsulated packet
- * ends up as multicast or broadcast packet.
+ * Check if the packet is comming via bridge and needs
+ * etherip encapsulation or not. bridge(4) directly calls
+ * the start function and bypasses the if_output function
+ * so we need to do the encap here.
*/
- m->m_flags &= ~(M_BCAST|M_MCAST);
-
- /* extract address family */
- family = AF_UNSPEC;
- tp = *mtod(m, u_int8_t *);
- tp = (tp >> 4) & 0xff; /* Get the IP version number. */
+ if (ifp->if_bridge && (m->m_flags & M_PROTO1)) {
+ int error = 0;
+ /*
+ * Remove multicast and broadcast flags or encapsulated
+ * packet ends up as multicast or broadcast packet.
+ */
+ m->m_flags &= ~(M_BCAST|M_MCAST);
+ switch (sc->gif_psrc->sa_family) {
#ifdef INET
- if (tp == IPVERSION)
- family = AF_INET;
+ case AF_INET:
+ error = in_gif_output(ifp, AF_LINK, &m);
+ break;
#endif
#ifdef INET6
- if (tp == (IPV6_VERSION >> 4))
- family = AF_INET6;
+ case AF_INET6:
+ error = in6_gif_output(ifp, AF_LINK, &m);
+ break;
#endif
-
-#if NBRIDGE > 0
- /*
- * Check if the packet is comming via bridge and needs
- * etherip encapsulation or not.
- */
- if (ifp->if_bridge && (m->m_flags & M_PROTO1)) {
- m->m_flags &= ~M_PROTO1;
- family = AF_LINK;
+ default:
+ error = EAFNOSUPPORT;
+ m_freem(m);
+ break;
+ }
+ if (error)
+ continue;
+ if (gif_checkloop(ifp, m))
+ continue;
}
-#endif
#if NBPFILTER > 0
- if (ifp->if_bpf)
+ if (ifp->if_bpf) {
+ int offset;
+ sa_family_t family;
+ u_int8_t proto;
+
+ /* must decapsulate outer header for bpf */
+ switch (sc->gif_psrc->sa_family) {
+#ifdef INET
+ case AF_INET:
+ offset = sizeof(struct ip);
+ proto = mtod(m, struct ip *)->ip_p;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ offset = sizeof(struct ip6_hdr);
+ proto = mtod(m, struct ip6_hdr *)->ip6_nxt;
+ break;
+#endif
+ default:
+ proto = 0;
+ break;
+ }
+ switch (proto) {
+ case IPPROTO_IPV4:
+ family = AF_INET;
+ break;
+ case IPPROTO_IPV6:
+ family = AF_INET6;
+ break;
+ case IPPROTO_ETHERIP:
+ family = AF_LINK;
+ break;
+ case IPPROTO_MPLS:
+ family = AF_MPLS;
+ break;
+ default:
+ offset = 0;
+ family = sc->gif_psrc->sa_family;
+ break;
+ }
+ m->m_data += offset;
+ m->m_len -= offset;
+ m->m_pkthdr.len -= offset;
bpf_mtap_af(ifp->if_bpf, family, m, BPF_DIRECTION_OUT);
+ m->m_data -= offset;
+ m->m_len += offset;
+ m->m_pkthdr.len += offset;
+ }
#endif
ifp->if_opackets++;
+ /* XXX we should cache the outgoing route */
+
switch (sc->gif_psrc->sa_family) {
#ifdef INET
case AF_INET:
- in_gif_output(ifp, family, m);
+ ip_output(m, (void *)NULL, (void *)NULL, 0,
+ (void *)NULL, (void *)NULL);
break;
#endif
#ifdef INET6
case AF_INET6:
- in6_gif_output(ifp, family, m);
+ /*
+ * force fragmentation to minimum MTU, to avoid path
+ * MTU discovery. It is too painful to ask for resend
+ * of inner packet, to achieve path MTU discovery for
+ * encapsulated packets.
+ */
+ ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL,
+ NULL);
break;
#endif
default:
@@ -259,44 +293,61 @@ gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
struct gif_softc *sc = (struct gif_softc*)ifp;
int error = 0;
int s;
+ sa_family_t family = dst->sa_family;
if (!(ifp->if_flags & IFF_UP) ||
- sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
+ sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
+ sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) {
m_freem(m);
error = ENETDOWN;
goto end;
}
+ /*
+ * Remove multicast and broadcast flags or encapsulated packet
+ * ends up as multicast or broadcast packet.
+ */
+ m->m_flags &= ~(M_BCAST|M_MCAST);
+
+ /*
+ * Encapsulate packet. Add IP or IP6 header depending on tunnel AF.
+ */
switch (sc->gif_psrc->sa_family) {
#ifdef INET
case AF_INET:
+ error = in_gif_output(ifp, family, &m);
break;
#endif
#ifdef INET6
case AF_INET6:
+ error = in6_gif_output(ifp, family, &m);
break;
#endif
default:
m_freem(m);
- error = ENETDOWN;
- goto end;
+ error = EAFNOSUPPORT;
+ break;
}
- s = splnet();
+ if (error)
+ goto end;
+
+ if ((error = gif_checkloop(ifp, m)))
+ goto end;
+
/*
- * Queue message on interface, and start output if interface
- * not yet active.
+ * Queue message on interface, and start output.
*/
+ s = splnet();
IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
if (error) {
/* mbuf is already freed */
splx(s);
- return (error);
+ goto end;
}
ifp->if_obytes += m->m_pkthdr.len;
if_start(ifp);
splx(s);
- return (error);
end:
if (error)
@@ -617,3 +668,33 @@ gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
bad:
return (error);
}
+
+int
+gif_checkloop(struct ifnet *ifp, struct mbuf *m)
+{
+ struct m_tag *mtag;
+
+ /*
+ * gif may cause infinite recursion calls when misconfigured.
+ * We'll prevent this by detecting loops.
+ */
+ for (mtag = m_tag_find(m, PACKET_TAG_GIF, NULL); mtag;
+ mtag = m_tag_find(m, PACKET_TAG_GIF, mtag)) {
+ if (!bcmp((caddr_t)(mtag + 1), &ifp,
+ sizeof(struct ifnet *))) {
+ log(LOG_NOTICE, "gif_output: "
+ "recursively called too many times\n");
+ m_freem(m);
+ return ENETUNREACH;
+ }
+ }
+
+ mtag = m_tag_get(PACKET_TAG_GIF, sizeof(caddr_t), M_NOWAIT);
+ if (mtag == NULL) {
+ m_freem(m);
+ return ENOMEM;
+ }
+ bcopy(&ifp, mtag + 1, sizeof(caddr_t));
+ m_tag_prepend(m, mtag);
+ return 0;
+}
diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c
index e2a92c0c57c..3cf02f75490 100644
--- a/sys/netinet/in_gif.c
+++ b/sys/netinet/in_gif.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_gif.c,v 1.37 2009/11/21 14:08:14 claudio Exp $ */
+/* $OpenBSD: in_gif.c,v 1.38 2010/05/11 09:36:07 claudio Exp $ */
/* $KAME: in_gif.c,v 1.50 2001/01/22 07:27:16 itojun Exp $ */
/*
@@ -54,13 +54,16 @@
#include "gif.h"
#include "bridge.h"
+#if NBRIDGE > 0
+#include <netinet/ip_ether.h>
+#endif
#if NPF > 0
#include <net/pfvar.h>
#endif
int
-in_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
+in_gif_output(struct ifnet *ifp, int family, struct mbuf **m0)
{
struct gif_softc *sc = (struct gif_softc*)ifp;
struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc;
@@ -68,7 +71,7 @@ in_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
struct tdb tdb;
struct xformsw xfs;
int error;
- struct mbuf *mp;
+ struct mbuf *m = *m0;
if (sin_src == NULL || sin_dst == NULL ||
sin_src->sin_family != AF_INET ||
@@ -85,7 +88,7 @@ in_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
}
#endif
- /* setup dummy tdb. it highly depends on ipipoutput() code. */
+ /* setup dummy tdb. it highly depends on ipip_output() code. */
bzero(&tdb, sizeof(tdb));
bzero(&xfs, sizeof(xfs));
tdb.tdb_src.sin.sin_family = AF_INET;
@@ -107,7 +110,11 @@ in_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
#if NBRIDGE > 0
case AF_LINK:
break;
-#endif /* NBRIDGE */
+#endif
+#if MPLS
+ case AF_MPLS:
+ break;
+#endif
default:
#ifdef DEBUG
printf("in_gif_output: warning: unknown family %d passed\n",
@@ -118,26 +125,30 @@ in_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
}
/* encapsulate into IPv4 packet */
- mp = NULL;
+ *m0 = NULL;
#if NBRIDGE > 0
if (family == AF_LINK)
- error = etherip_output(m, &tdb, &mp, 0, 0);
+ error = etherip_output(m, &tdb, m0, IPPROTO_ETHERIP);
else
#endif /* NBRIDGE */
- error = ipip_output(m, &tdb, &mp, 0, 0);
+#ifdef MPLS
+ if (family == AF_MPLS)
+ error = etherip_output(m, &tdb, m0, IPPROTO_MPLS);
+ else
+#endif
+ error = ipip_output(m, &tdb, m0, 0, 0);
if (error)
return error;
- else if (mp == NULL)
+ else if (*m0 == NULL)
return EFAULT;
- m = mp;
+ m = *m0;
m->m_pkthdr.rdomain = sc->gif_rtableid;
#if NPF > 0
pf_pkt_addr_changed(m);
#endif
- return ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL,
- (void *)NULL);
+ return 0;
}
void
@@ -186,7 +197,8 @@ in_gif_input(struct mbuf *m, ...)
m->m_pkthdr.rdomain = gifp->if_rdomain;
gifp->if_ipackets++;
gifp->if_ibytes += m->m_pkthdr.len;
- ipip_input(m, off, gifp); /* We have a configured GIF */
+ /* We have a configured GIF */
+ ipip_input(m, off, gifp, ip->ip_p);
return;
}
diff --git a/sys/netinet/in_gif.h b/sys/netinet/in_gif.h
index 3a12d06dd91..aa4b660a2b6 100644
--- a/sys/netinet/in_gif.h
+++ b/sys/netinet/in_gif.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_gif.h,v 1.5 2007/02/10 15:34:22 claudio Exp $ */
+/* $OpenBSD: in_gif.h,v 1.6 2010/05/11 09:36:07 claudio Exp $ */
/* $KAME: in_gif.h,v 1.5 2000/04/14 08:36:02 itojun Exp $ */
/*
@@ -34,6 +34,6 @@
#define _NETINET_IN_GIF_H_
void in_gif_input(struct mbuf *, ...);
-int in_gif_output(struct ifnet *, int, struct mbuf *);
+int in_gif_output(struct ifnet *, int, struct mbuf **);
#endif /*_NETINET_IN_GIF_H_*/
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index f30b585dc4a..0ecac5bd043 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_proto.c,v 1.52 2010/01/12 23:33:24 yasuoka Exp $ */
+/* $OpenBSD: in_proto.c,v 1.53 2010/05/11 09:36:07 claudio Exp $ */
/* $NetBSD: in_proto.c,v 1.14 1996/02/18 18:58:32 christos Exp $ */
/*
@@ -210,13 +210,25 @@ struct protosw inetsw[] = {
rip_usrreq,
0, 0, 0, 0, ipip_sysctl
},
+{ SOCK_RAW, &inetdomain, IPPROTO_ETHERIP, PR_ATOMIC|PR_ADDR,
+ etherip_input, rip_output, 0, rip_ctloutput,
+ rip_usrreq,
+ 0, 0, 0, 0, etherip_sysctl
+},
#ifdef INET6
{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR,
in_gif_input, rip_output, 0, 0,
rip_usrreq, /*XXX*/
0, 0, 0, 0,
},
-#endif /* INET6 */
+#endif
+#ifdef MPLS
+{ SOCK_RAW, &inetdomain, IPPROTO_MPLS, PR_ATOMIC|PR_ADDR,
+ etherip_input, rip_output, 0, 0,
+ rip_usrreq,
+ 0, 0, 0, 0,
+},
+#endif
#else /* NGIF */
{ SOCK_RAW, &inetdomain, IPPROTO_IPIP, PR_ATOMIC|PR_ADDR,
ip4_input, rip_output, 0, rip_ctloutput,
@@ -229,7 +241,7 @@ struct protosw inetsw[] = {
rip_usrreq, /*XXX*/
0, 0, 0, 0,
},
-#endif /* INET6 */
+#endif
#endif /*NGIF*/
{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR,
igmp_input, rip_output, 0, rip_ctloutput,
@@ -254,11 +266,6 @@ struct protosw inetsw[] = {
rip_usrreq,
0, 0, 0, 0, esp_sysctl
},
-{ SOCK_RAW, &inetdomain, IPPROTO_ETHERIP, PR_ATOMIC|PR_ADDR,
- etherip_input, rip_output, 0, rip_ctloutput,
- rip_usrreq,
- 0, 0, 0, 0, etherip_sysctl
-},
{ SOCK_RAW, &inetdomain, IPPROTO_IPCOMP, PR_ATOMIC|PR_ADDR,
ipcomp4_input, rip_output, 0, rip_ctloutput,
rip_usrreq,
diff --git a/sys/netinet/ip_ether.c b/sys/netinet/ip_ether.c
index d337aee1bac..1a40db89819 100644
--- a/sys/netinet/ip_ether.c
+++ b/sys/netinet/ip_ether.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ether.c,v 1.53 2010/04/20 22:05:43 tedu Exp $ */
+/* $OpenBSD: ip_ether.c,v 1.54 2010/05/11 09:36:07 claudio Exp $ */
/*
* The author of this code is Angelos D. Keromytis (kermit@adk.gr)
*
@@ -35,9 +35,10 @@
#include <sys/proc.h>
#include <sys/sysctl.h>
+#include <net/bpf.h>
#include <net/if.h>
+#include <net/netisr.h>
#include <net/route.h>
-#include <net/bpf.h>
#ifdef INET
#include <netinet/in.h>
@@ -49,10 +50,16 @@
#include <netinet/ip_ether.h>
#include <netinet/if_ether.h>
-#include <net/if_bridge.h>
+
#include <net/if_gif.h>
-#include "gif.h"
+#if NBRIDGE > 0
+#include <net/if_bridge.h>
+#endif
+#ifdef MPLS
+#include <netmpls/mpls.h>
+#endif
+
#include "bpfilter.h"
#ifdef ENCDEBUG
@@ -61,6 +68,14 @@
#define DPRINTF(x)
#endif
+#if NBRIDGE > 0
+void etherip_decap(struct mbuf *, int);
+#endif
+#ifdef MPLS
+void mplsip_decap(struct mbuf *, int);
+#endif
+struct gif_softc *etherip_getgif(struct mbuf *);
+
/*
* We can control the acceptance of EtherIP packets by altering the sysctl
* net.inet.etherip.allow value. Zero means drop them, all else is acceptance.
@@ -69,43 +84,93 @@ int etherip_allow = 0;
struct etheripstat etheripstat;
+#ifdef INET
/*
- * etherip_input gets called when we receive an encapsulated packet,
- * either because we got it at a real interface, or because AH or ESP
- * were being used in tunnel mode (in which case the rcvif element will
- * contain the address of the encX interface associated with the tunnel.
+ * etherip_input gets called when we receive an encapsulated packet.
+ * Only a wrapper for the IPv4 case.
*/
-
void
etherip_input(struct mbuf *m, ...)
{
- union sockaddr_union ssrc, sdst;
- struct ether_header eh;
- int iphlen;
- struct etherip_header eip;
- u_int8_t v;
+ struct ip *ip;
va_list ap;
+ int iphlen;
-#if NGIF > 0
- struct gif_softc *sc;
-#if NBRIDGE > 0
- int s;
-#endif /* NBRIDGE */
-#endif /* NGIF */
+ ip = mtod(m, struct ip *);
va_start(ap, m);
iphlen = va_arg(ap, int);
va_end(ap);
- etheripstat.etherip_ipackets++;
-
- /* If we do not accept EtherIP explicitly, drop. */
- if (!etherip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) {
- DPRINTF(("etherip_input(): dropped due to policy\n"));
+ switch (ip->ip_p) {
+#if NBRIDGE > 0
+ case IPPROTO_ETHERIP:
+ /* If we do not accept EtherIP explicitly, drop. */
+ if (!etherip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) {
+ DPRINTF(("etherip_input(): dropped due to policy\n"));
+ etheripstat.etherip_pdrops++;
+ m_freem(m);
+ return;
+ }
+ etherip_decap(m, iphlen);
+ return;
+#endif
+#ifdef MPLS
+ case IPPROTO_MPLS:
+ mplsip_decap(m, iphlen);
+ return;
+#endif
+ default:
+ DPRINTF(("etherip_input(): dropped, unhandled protcol \n"));
etheripstat.etherip_pdrops++;
m_freem(m);
return;
}
+}
+#endif
+
+#ifdef INET6
+int
+etherip_input6(struct mbuf **m, int *offp, int proto)
+{
+ switch (proto) {
+#if NBRIDGE > 0
+ case IPPROTO_ETHERIP:
+ /* If we do not accept EtherIP explicitly, drop. */
+ if (proto == IPPROTO_ETHERIP && !etherip_allow &&
+ ((*m)->m_flags & (M_AUTH|M_CONF)) == 0) {
+ DPRINTF(("etherip_input6(): dropped due to policy\n"));
+ etheripstat.etherip_pdrops++;
+ m_freem(*m);
+ return IPPROTO_DONE;
+ }
+ etherip_decap(*m, *offp);
+ return IPPROTO_DONE;
+#endif
+#ifdef MPLS
+ case IPPROTO_MPLS:
+ mplsip_decap(*m, *offp);
+ return IPPROTO_DONE;
+#endif
+ default:
+ DPRINTF(("etherip_input6(): dropped, unhandled protcol \n"));
+ etheripstat.etherip_pdrops++;
+ m_freem(*m);
+ return IPPROTO_DONE;
+ }
+}
+#endif
+
+#if NBRIDGE > 0
+void
+etherip_decap(struct mbuf *m, int iphlen)
+{
+ struct ether_header eh;
+ struct etherip_header eip;
+ struct gif_softc *sc;
+ int s;
+
+ etheripstat.etherip_ipackets++;
/*
* Make sure there's at least an ethernet header's and an EtherIP
@@ -123,7 +188,7 @@ etherip_input(struct mbuf *m, ...)
m_copydata(m, iphlen, sizeof(struct etherip_header), (caddr_t)&eip);
if ((eip.eip_ver & ETHERIP_VER_VERS_MASK) != ETHERIP_VERSION) {
DPRINTF(("etherip_input(): received EtherIP version number "
- "%d not suppoorted\n", (v >> 4) & 0xff));
+ "%d not suppoorted\n", eip.eip_ver));
etheripstat.etherip_adrops++;
m_freem(m);
return;
@@ -162,6 +227,149 @@ etherip_input(struct mbuf *m, ...)
}
}
+ sc = etherip_getgif(m);
+ if (sc == NULL)
+ return;
+ if (sc->gif_if.if_bridge == NULL) {
+ DPRINTF(("etherip_input(): interface not part of bridge\n"));
+ etheripstat.etherip_noifdrops++;
+ m_freem(m);
+ return;
+ }
+
+ /* Chop off the `outer' IP and EtherIP headers and reschedule. */
+ m_adj(m, iphlen + sizeof(struct etherip_header));
+
+ /* Statistics */
+ etheripstat.etherip_ibytes += m->m_pkthdr.len;
+
+ /* Copy ethernet header */
+ m_copydata(m, 0, sizeof(eh), (void *) &eh);
+
+ /* Reset the flags based on the inner packet */
+ m->m_flags &= ~(M_BCAST|M_MCAST|M_AUTH|M_CONF|M_AUTH_AH);
+ if (eh.ether_dhost[0] & 1) {
+ if (bcmp((caddr_t) etherbroadcastaddr,
+ (caddr_t)eh.ether_dhost, sizeof(etherbroadcastaddr)) == 0)
+ m->m_flags |= M_BCAST;
+ else
+ m->m_flags |= M_MCAST;
+ }
+
+#if NBPFILTER > 0
+ if (sc->gif_if.if_bpf)
+ bpf_mtap_af(sc->gif_if.if_bpf, AF_LINK, m, BPF_DIRECTION_IN);
+#endif
+
+ /* Trim the beginning of the mbuf, to remove the ethernet header. */
+ m_adj(m, sizeof(struct ether_header));
+
+ /*
+ * Tap the packet off here for a bridge. bridge_input() returns
+ * NULL if it has consumed the packet. In the case of gif's,
+ * bridge_input() returns non-NULL when an error occurs.
+ */
+#if NPF > 0
+ pf_pkt_addr_changed(m);
+#endif
+ m->m_pkthdr.rcvif = &sc->gif_if;
+ m->m_pkthdr.rdomain = sc->gif_if.if_rdomain;
+ if (m->m_flags & (M_BCAST|M_MCAST))
+ sc->gif_if.if_imcasts++;
+
+ s = splnet();
+ m = bridge_input(&sc->gif_if, &eh, m);
+ splx(s);
+ if (m == NULL)
+ return;
+
+ etheripstat.etherip_noifdrops++;
+ m_freem(m);
+ return;
+}
+#endif
+
+#ifdef MPLS
+void
+mplsip_decap(struct mbuf *m, int iphlen)
+{
+ struct gif_softc *sc;
+ struct ifqueue *ifq;
+ int s;
+
+ etheripstat.etherip_ipackets++;
+
+ /*
+ * Make sure there's at least one MPLS label worth of data after
+ * the outer IP header.
+ */
+ if (m->m_pkthdr.len < iphlen + sizeof(struct shim_hdr)) {
+ DPRINTF(("mplsip_input(): encapsulated packet too short\n"));
+ etheripstat.etherip_hdrops++;
+ m_freem(m);
+ return;
+ }
+
+ /* Make sure the mpls label at least is in the first mbuf. */
+ if (m->m_len < iphlen + sizeof(struct shim_hdr)) {
+ if ((m = m_pullup(m, iphlen + sizeof(struct shim_hdr))) ==
+ NULL) {
+ DPRINTF(("mplsip_input(): m_pullup() failed\n"));
+ etheripstat.etherip_adrops++;
+ return;
+ }
+ }
+
+ sc = etherip_getgif(m);
+ if (sc == NULL)
+ return;
+
+ /* Chop off the `outer' IP header and reschedule. */
+ m_adj(m, iphlen);
+
+ /* Statistics */
+ etheripstat.etherip_ibytes += m->m_pkthdr.len;
+
+ /* Reset the flags based */
+ m->m_flags &= ~(M_BCAST|M_MCAST);
+
+#if NBPFILTER > 0
+ if (sc->gif_if.if_bpf)
+ bpf_mtap_af(sc->gif_if.if_bpf, AF_MPLS, m, BPF_DIRECTION_IN);
+#endif
+
+ m->m_pkthdr.rcvif = &sc->gif_if;
+ m->m_pkthdr.rdomain = sc->gif_if.if_rdomain;
+#if NPF > 0
+ pf_pkt_addr_changed(m);
+#endif
+
+ ifq = &mplsintrq;
+ s = splnet();
+ if (IF_QFULL(ifq)) {
+ IF_DROP(ifq);
+ m_freem(m);
+ etheripstat.etherip_qfull++;
+ splx(s);
+
+ DPRINTF(("mplsip_input(): packet dropped because of full "
+ "queue\n"));
+ return;
+ }
+ IF_ENQUEUE(ifq, m);
+ schednetisr(NETISR_MPLS);
+ splx(s);
+ return;
+}
+#endif
+
+struct gif_softc *
+etherip_getgif(struct mbuf *m)
+{
+ union sockaddr_union ssrc, sdst;
+ struct gif_softc *sc;
+ u_int8_t v;
+
/* Copy the addresses for use later. */
bzero(&ssrc, sizeof(ssrc));
bzero(&sdst, sizeof(sdst));
@@ -196,29 +404,9 @@ etherip_input(struct mbuf *m, ...)
DPRINTF(("etherip_input(): invalid protocol %d\n", v));
m_freem(m);
etheripstat.etherip_hdrops++;
- return /* EAFNOSUPPORT */;
+ return NULL;
}
- /* Chop off the `outer' IP and EtherIP headers and reschedule. */
- m_adj(m, iphlen + sizeof(struct etherip_header));
-
- /* Statistics */
- etheripstat.etherip_ibytes += m->m_pkthdr.len;
-
- /* Copy ethernet header */
- m_copydata(m, 0, sizeof(eh), (void *) &eh);
-
- /* Reset the flags based on the inner packet */
- m->m_flags &= ~(M_BCAST|M_MCAST|M_AUTH|M_CONF|M_AUTH_AH);
- if (eh.ether_dhost[0] & 1) {
- if (bcmp((caddr_t) etherbroadcastaddr,
- (caddr_t)eh.ether_dhost, sizeof(etherbroadcastaddr)) == 0)
- m->m_flags |= M_BCAST;
- else
- m->m_flags |= M_MCAST;
- }
-
-#if NGIF > 0
/* Find appropriate gif(4) interface */
LIST_FOREACH(sc, &gif_softc_list, gif_list) {
if ((sc->gif_psrc == NULL) ||
@@ -227,8 +415,7 @@ etherip_input(struct mbuf *m, ...)
continue;
if (!bcmp(sc->gif_psrc, &sdst, sc->gif_psrc->sa_len) &&
- !bcmp(sc->gif_pdst, &ssrc, sc->gif_pdst->sa_len) &&
- sc->gif_if.if_bridge != NULL)
+ !bcmp(sc->gif_pdst, &ssrc, sc->gif_pdst->sa_len))
break;
}
@@ -237,54 +424,22 @@ etherip_input(struct mbuf *m, ...)
DPRINTF(("etherip_input(): no interface found\n"));
etheripstat.etherip_noifdrops++;
m_freem(m);
- return;
+ return NULL;
}
-#if NBPFILTER > 0
- if (sc->gif_if.if_bpf)
- bpf_mtap_af(sc->gif_if.if_bpf, AF_LINK, m, BPF_DIRECTION_IN);
-#endif
-
- /* Trim the beginning of the mbuf, to remove the ethernet header. */
- m_adj(m, sizeof(struct ether_header));
-#if NBRIDGE > 0
- /*
- * Tap the packet off here for a bridge. bridge_input() returns
- * NULL if it has consumed the packet. In the case of gif's,
- * bridge_input() returns non-NULL when an error occurs.
- */
- m->m_pkthdr.rcvif = &sc->gif_if;
- m->m_pkthdr.rdomain = sc->gif_if.if_rdomain;
- if (m->m_flags & (M_BCAST|M_MCAST))
- sc->gif_if.if_imcasts++;
-
- s = splnet();
- m = bridge_input(&sc->gif_if, &eh, m);
- splx(s);
- if (m == NULL)
- return;
-#endif /* NBRIDGE */
-#endif /* NGIF */
-
- etheripstat.etherip_noifdrops++;
- m_freem(m);
- return;
+ return sc;
}
int
-etherip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
- int protoff)
+etherip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int proto)
{
#ifdef INET
struct ip *ipo;
#endif /* INET */
-
#ifdef INET6
struct ip6_hdr *ip6;
#endif /* INET6 */
-
struct etherip_header eip;
- struct mbuf *m0;
ushort hlen;
/* Some address family sanity checks. */
@@ -335,27 +490,16 @@ etherip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
return EINVAL;
}
- /* Don't forget the EtherIP header. */
- hlen += sizeof(struct etherip_header);
-
- if (!(m->m_flags & M_PKTHDR)) {
- DPRINTF(("etherip_output(): mbuf is not a header\n"));
- m_freem(m);
- return (ENOBUFS);
- }
+ if (proto == IPPROTO_ETHERIP)
+ /* Don't forget the EtherIP header. */
+ hlen += sizeof(struct etherip_header);
- MGETHDR(m0, M_DONTWAIT, MT_DATA);
- if (m0 == NULL) {
- DPRINTF(("etherip_output(): M_GETHDR failed\n"));
+ M_PREPEND(m, hlen, M_DONTWAIT);
+ if (m == NULL) {
+ DPRINTF(("etherip_output(): M_PREPEND failed\n"));
etheripstat.etherip_adrops++;
- m_freem(m);
return ENOBUFS;
}
- M_MOVE_PKTHDR(m0, m);
- m0->m_next = m;
- m0->m_len = hlen;
- m0->m_pkthdr.len += hlen;
- m = m0;
/* Statistics */
etheripstat.etherip_opackets++;
@@ -370,7 +514,7 @@ etherip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
ipo->ip_hl = 5;
ipo->ip_len = htons(m->m_pkthdr.len);
ipo->ip_ttl = ip_defttl;
- ipo->ip_p = IPPROTO_ETHERIP;
+ ipo->ip_p = proto;
ipo->ip_tos = 0;
ipo->ip_off = 0;
ipo->ip_sum = 0;
@@ -390,7 +534,7 @@ etherip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_flow = 0;
- ip6->ip6_nxt = IPPROTO_ETHERIP;
+ ip6->ip6_nxt = proto;
ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
ip6->ip6_vfc |= IPV6_VERSION;
ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
@@ -401,11 +545,13 @@ etherip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
#endif /* INET6 */
}
- /* Set the version number */
- eip.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK;
- eip.eip_pad = 0;
- m_copyback(m, hlen - sizeof(struct etherip_header),
- sizeof(struct etherip_header), &eip);
+ if (proto == IPPROTO_ETHERIP) {
+ /* Set the version number */
+ eip.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK;
+ eip.eip_pad = 0;
+ m_copyback(m, hlen - sizeof(struct etherip_header),
+ sizeof(struct etherip_header), &eip);
+ }
*mp = m;
diff --git a/sys/netinet/ip_ether.h b/sys/netinet/ip_ether.h
index c2372557bd6..3eca19bf521 100644
--- a/sys/netinet/ip_ether.h
+++ b/sys/netinet/ip_ether.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ether.h,v 1.14 2007/12/14 18:33:41 deraadt Exp $ */
+/* $OpenBSD: ip_ether.h,v 1.15 2010/05/11 09:36:07 claudio Exp $ */
/*
* The author of this code is Angelos D. Keromytis (angelos@adk.gr)
*
@@ -64,6 +64,11 @@ struct etherip_header {
}
#ifdef _KERNEL
+int etherip_output(struct mbuf *, struct tdb *, struct mbuf **, int);
+void etherip_input(struct mbuf *, ...);
+#ifdef INET6
+int etherip_input6(struct mbuf **, int *, int);
+#endif
int etherip_sysctl(int *, u_int, void *, size_t *, void *, size_t);
extern int etherip_allow;
diff --git a/sys/netinet/ip_ipip.c b/sys/netinet/ip_ipip.c
index b67f20a566a..6a48e52bb0b 100644
--- a/sys/netinet/ip_ipip.c
+++ b/sys/netinet/ip_ipip.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipip.c,v 1.46 2010/04/20 22:05:43 tedu Exp $ */
+/* $OpenBSD: ip_ipip.c,v 1.47 2010/05/11 09:36:07 claudio Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
@@ -103,7 +103,7 @@ ip4_input6(struct mbuf **m, int *offp, int proto)
return IPPROTO_DONE;
}
- ipip_input(*m, *offp, NULL);
+ ipip_input(*m, *offp, NULL, proto);
return IPPROTO_DONE;
}
#endif /* INET6 */
@@ -115,6 +115,7 @@ ip4_input6(struct mbuf **m, int *offp, int proto)
void
ip4_input(struct mbuf *m, ...)
{
+ struct ip *ip;
va_list ap;
int iphlen;
@@ -130,7 +131,9 @@ ip4_input(struct mbuf *m, ...)
iphlen = va_arg(ap, int);
va_end(ap);
- ipip_input(m, iphlen, NULL);
+ ip = mtod(m, struct ip *);
+
+ ipip_input(m, iphlen, NULL, ip->ip_p);
}
#endif /* INET */
@@ -142,7 +145,7 @@ ip4_input(struct mbuf *m, ...)
*/
void
-ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
+ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp, int proto)
{
struct sockaddr_in *sin;
struct ifnet *ifp;
@@ -152,13 +155,14 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
u_int rdomain;
#ifdef INET6
struct sockaddr_in6 *sin6;
- struct ip6_hdr *ip6 = NULL;
+ struct ip6_hdr *ip6;
u_int8_t itos;
#endif
int isr;
+ int hlen, s;
u_int8_t otos;
u_int8_t v;
- int hlen, s;
+ sa_family_t af;
ipipstat.ipips_ipackets++;
@@ -166,16 +170,16 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
switch (v >> 4) {
#ifdef INET
- case 4:
+ case 4:
hlen = sizeof(struct ip);
break;
#endif /* INET */
#ifdef INET6
- case 6:
+ case 6:
hlen = sizeof(struct ip6_hdr);
break;
#endif
- default:
+ default:
ipipstat.ipips_family++;
m_freem(m);
return /* EAFNOSUPPORT */;
@@ -190,18 +194,19 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
}
}
- ipo = mtod(m, struct ip *);
/* Keep outer ecn field. */
switch (v >> 4) {
#ifdef INET
case 4:
+ ipo = mtod(m, struct ip *);
otos = ipo->ip_tos;
break;
#endif /* INET */
#ifdef INET6
case 6:
- otos = (ntohl(mtod(m, struct ip6_hdr *)->ip6_flow) >> 20) & 0xff;
+ ip6 = mtod(m, struct ip6_hdr *);
+ otos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
break;
#endif
default:
@@ -218,17 +223,15 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
return;
}
- m_copydata(m, 0, 1, &v);
-
- switch (v >> 4) {
+ switch (proto) {
#ifdef INET
- case 4:
+ case IPPROTO_IPV4:
hlen = sizeof(struct ip);
break;
#endif /* INET */
#ifdef INET6
- case 6:
+ case IPPROTO_IPV6:
hlen = sizeof(struct ip6_hdr);
break;
#endif
@@ -239,7 +242,7 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
}
/*
- * Bring the inner IP header in the first mbuf, if not there already.
+ * Bring the inner header into the first mbuf, if not there already.
*/
if (m->m_len < hlen) {
if ((m = m_pullup(m, hlen)) == NULL) {
@@ -256,19 +259,25 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
*/
/* Some sanity checks in the inner IP header */
- switch (v >> 4) {
+ switch (proto) {
#ifdef INET
- case 4:
- ipo = mtod(m, struct ip *);
+ case IPPROTO_IPV4:
+ ipo = mtod(m, struct ip *);
+#ifdef INET6
+ ip6 = NULL;
+#endif
if (!ip_ecn_egress(ECN_ALLOWED, &otos, &ipo->ip_tos)) {
m_freem(m);
return;
}
- break;
+ break;
#endif /* INET */
#ifdef INET6
- case 6:
- ip6 = (struct ip6_hdr *) ipo;
+ case IPPROTO_IPV6:
+#ifdef INET
+ ipo = NULL;
+#endif
+ ip6 = mtod(m, struct ip6_hdr *);
itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos)) {
m_freem(m);
@@ -276,10 +285,15 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
}
ip6->ip6_flow &= ~htonl(0xff << 20);
ip6->ip6_flow |= htonl((u_int32_t) itos << 20);
- break;
+ break;
#endif
default:
- panic("ipip_input: should never reach here");
+#ifdef INET
+ ipo = NULL;
+#endif
+#ifdef INET6
+ ip6 = NULL;
+#endif
}
/* Check for local address spoofing. */
@@ -297,8 +311,8 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
AF_INET)
continue;
- sin = (struct sockaddr_in *) ifa->ifa_addr;
-
+ sin = (struct sockaddr_in *)
+ ifa->ifa_addr;
if (sin->sin_addr.s_addr ==
ipo->ip_src.s_addr) {
ipipstat.ipips_spoof++;
@@ -307,16 +321,16 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
}
}
#endif /* INET */
-
#ifdef INET6
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)) {
+ sin6 = (struct sockaddr_in6 *)
+ ifa->ifa_addr;
+ if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
+ &ip6->ip6_src)) {
ipipstat.ipips_spoof++;
m_freem(m);
return;
@@ -339,17 +353,19 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
* untrusted packets.
*/
- switch (v >> 4) {
+ switch (proto) {
#ifdef INET
- case 4:
+ case IPPROTO_IPV4:
ifq = &ipintrq;
isr = NETISR_IP;
+ af = AF_INET;
break;
#endif
#ifdef INET6
- case 6:
+ case IPPROTO_IPV6:
ifq = &ip6intrq;
isr = NETISR_IPV6;
+ af = AF_INET6;
break;
#endif
default:
@@ -358,8 +374,7 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
#if NBPFILTER > 0
if (gifp && gifp->if_bpf)
- bpf_mtap_af(gifp->if_bpf, ifq == &ipintrq ? AF_INET : AF_INET6,
- m, BPF_DIRECTION_IN);
+ bpf_mtap_af(gifp->if_bpf, af, m, BPF_DIRECTION_IN);
#endif
#if NPF > 0
pf_pkt_addr_changed(m);
diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h
index 01eb0282ffe..8d8f14323d0 100644
--- a/sys/netinet/ip_ipsp.h
+++ b/sys/netinet/ip_ipsp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.h,v 1.141 2010/05/07 13:33:17 claudio Exp $ */
+/* $OpenBSD: ip_ipsp.h,v 1.142 2010/05/11 09:36:07 claudio Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr),
@@ -534,7 +534,7 @@ extern int ipe4_init(struct tdb *, struct xformsw *, struct ipsecinit *);
extern int ipe4_zeroize(struct tdb *);
extern int ipip_output(struct mbuf *, struct tdb *, struct mbuf **, int, int);
extern void ipe4_input(struct mbuf *, ...);
-extern void ipip_input(struct mbuf *, int, struct ifnet *);
+extern void ipip_input(struct mbuf *, int, struct ifnet *, int);
#ifdef INET
extern void ip4_input(struct mbuf *, ...);
@@ -544,11 +544,6 @@ extern void ip4_input(struct mbuf *, ...);
extern int ip4_input6(struct mbuf **, int *, int);
#endif /* INET */
-/* XF_ETHERIP */
-extern int etherip_output(struct mbuf *, struct tdb *, struct mbuf **,
- int, int);
-extern void etherip_input(struct mbuf *, ...);
-
/* XF_AH */
extern int ah_attach(void);
extern int ah_init(struct tdb *, struct xformsw *, struct ipsecinit *);
diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c
index f5ed9e3595d..2e37eb823b6 100644
--- a/sys/netinet6/in6_gif.c
+++ b/sys/netinet6/in6_gif.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6_gif.c,v 1.28 2010/05/07 13:33:17 claudio Exp $ */
+/* $OpenBSD: in6_gif.c,v 1.29 2010/05/11 09:36:07 claudio Exp $ */
/* $KAME: in6_gif.c,v 1.43 2001/01/22 07:27:17 itojun Exp $ */
/*
@@ -60,15 +60,14 @@
#include <netinet6/ip6_var.h>
#include <netinet6/in6_gif.h>
-#ifdef INET6
-#include <netinet/ip6.h>
-#endif
-
#include <netinet/ip_ecn.h>
#include <net/if_gif.h>
#include "bridge.h"
+#if NBRIDGE > 0
+#include <netinet/ip_ether.h>
+#endif
#ifndef offsetof
#define offsetof(s, e) ((int)&((s *)0)->e)
@@ -78,16 +77,15 @@
* family - family of the packet to be encapsulate.
*/
int
-in6_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
+in6_gif_output(struct ifnet *ifp, int family, struct mbuf **m0)
{
struct gif_softc *sc = (struct gif_softc*)ifp;
- struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
struct tdb tdb;
struct xformsw xfs;
int error;
- struct mbuf *mp;
+ struct mbuf *m = *m0;
if (sin6_src == NULL || sin6_dst == NULL ||
sin6_src->sin6_family != AF_INET6 ||
@@ -120,7 +118,11 @@ in6_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
#if NBRIDGE > 0
case AF_LINK:
break;
-#endif /* NBRIDGE */
+#endif
+#ifdef MPLS
+ case AF_MPLS:
+ break;
+#endif
default:
#ifdef DEBUG
printf("in6_gif_output: warning: unknown family %d passed\n",
@@ -131,55 +133,29 @@ in6_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
}
/* encapsulate into IPv6 packet */
- mp = NULL;
+ *m0 = NULL;
#if NBRIDGE > 0
if (family == AF_LINK)
- error = etherip_output(m, &tdb, &mp, 0, 0);
+ error = etherip_output(m, &tdb, m0, IPPROTO_ETHERIP);
else
#endif /* NBRIDGE */
- error = ipip_output(m, &tdb, &mp, 0, 0);
+#if MPLS
+ if (family == AF_MPLS)
+ error = etherip_output(m, &tdb, m0, IPPROTO_MPLS);
+ else
+#endif
+ error = ipip_output(m, &tdb, m0, 0, 0);
if (error)
return error;
- else if (mp == NULL)
+ else if (*m0 == NULL)
return EFAULT;
- m = mp;
-
- /* See if out cached route remains the same */
- if (dst->sin6_family != sin6_dst->sin6_family ||
- !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
- /* cache route doesn't match */
- bzero(dst, sizeof(*dst));
- dst->sin6_family = sin6_dst->sin6_family;
- dst->sin6_len = sizeof(struct sockaddr_in6);
- dst->sin6_addr = sin6_dst->sin6_addr;
- /* XXX rdomain */
- sc->gif_ro6.ro_tableid = 0;
- if (sc->gif_ro6.ro_rt) {
- RTFREE(sc->gif_ro6.ro_rt);
- sc->gif_ro6.ro_rt = NULL;
- }
- }
+ m = *m0;
- if (sc->gif_ro6.ro_rt == NULL) {
- rtalloc((struct route *)&sc->gif_ro6);
- if (sc->gif_ro6.ro_rt == NULL) {
- m_freem(m);
- return ENETUNREACH;
- }
- }
-
- /*
- * force fragmentation to minimum MTU, to avoid path MTU discovery.
- * it is too painful to ask for resend of inner packet, to achieve
- * path MTU discovery for encapsulated packets.
- */
#if NPF > 0
pf_pkt_addr_changed(m);
#endif
- error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL, NULL);
-
- return error;
+ return 0;
}
int in6_gif_input(struct mbuf **mp, int *offp, int proto)
@@ -217,12 +193,12 @@ int in6_gif_input(struct mbuf **mp, int *offp, int proto)
m->m_pkthdr.rcvif = gifp;
gifp->if_ipackets++;
gifp->if_ibytes += m->m_pkthdr.len;
- ipip_input(m, *offp, gifp);
+ ipip_input(m, *offp, gifp, proto);
return IPPROTO_DONE;
}
inject:
/* No GIF tunnel configured */
- ip4_input6(&m, offp, 0); /* XXX last argument ignored */
+ ip4_input6(&m, offp, proto);
return IPPROTO_DONE;
}
diff --git a/sys/netinet6/in6_gif.h b/sys/netinet6/in6_gif.h
index 209db1471b7..62713f69120 100644
--- a/sys/netinet6/in6_gif.h
+++ b/sys/netinet6/in6_gif.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6_gif.h,v 1.5 2007/02/10 15:34:22 claudio Exp $ */
+/* $OpenBSD: in6_gif.h,v 1.6 2010/05/11 09:36:07 claudio Exp $ */
/* $KAME: in6_gif.h,v 1.5 2000/04/14 08:36:03 itojun Exp $ */
/*
@@ -33,7 +33,7 @@
#ifndef _NETINET6_IN6_GIF_H_
#define _NETINET6_IN6_GIF_H_
+int in6_gif_output(struct ifnet *, int, struct mbuf **);
int in6_gif_input(struct mbuf **, int *, int);
-int in6_gif_output(struct ifnet *, int, struct mbuf *);
#endif /*_NETINET6_IN6_GIF_H_*/