diff options
-rw-r--r-- | sys/net/if_gif.c | 229 | ||||
-rw-r--r-- | sys/netinet/in_gif.c | 38 | ||||
-rw-r--r-- | sys/netinet/in_gif.h | 4 | ||||
-rw-r--r-- | sys/netinet/in_proto.c | 23 | ||||
-rw-r--r-- | sys/netinet/ip_ether.c | 362 | ||||
-rw-r--r-- | sys/netinet/ip_ether.h | 7 | ||||
-rw-r--r-- | sys/netinet/ip_ipip.c | 87 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.h | 9 | ||||
-rw-r--r-- | sys/netinet6/in6_gif.c | 72 | ||||
-rw-r--r-- | sys/netinet6/in6_gif.h | 4 |
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_*/ |