summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/in6_gif.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet6/in6_gif.c')
-rw-r--r--sys/netinet6/in6_gif.c153
1 files changed, 117 insertions, 36 deletions
diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c
index 35c4088..e554f5a 100644
--- a/sys/netinet6/in6_gif.c
+++ b/sys/netinet6/in6_gif.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: in6_gif.c,v 1.37 2000/06/17 20:34:25 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $FreeBSD$
*/
/*
@@ -34,6 +35,7 @@
*/
#include "opt_inet.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -41,7 +43,6 @@
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/errno.h>
-#include <sys/protosw.h>
#include <net/if.h>
#include <net/route.h>
@@ -51,17 +52,26 @@
#ifdef INET
#include <netinet/ip.h>
#endif
-#include <netinet6/ip6.h>
+#include <netinet/ip_encap.h>
+#ifdef INET6
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/in6_gif.h>
-#include <netinet6/ip6.h>
+#include <netinet6/in6_var.h>
+#endif
#include <netinet/ip_ecn.h>
+#ifdef INET6
#include <netinet6/ip6_ecn.h>
+#endif
#include <net/if_gif.h>
#include <net/net_osdep.h>
+#ifndef offsetof
+#define offsetof(s, e) ((int)&((s *)0)->e)
+#endif
+
int
in6_gif_output(ifp, family, m, rt)
struct ifnet *ifp;
@@ -101,6 +111,7 @@ in6_gif_output(ifp, family, m, rt)
break;
}
#endif
+#ifdef INET6
case AF_INET6:
{
struct ip6_hdr *ip6;
@@ -114,15 +125,16 @@ in6_gif_output(ifp, family, m, rt)
itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
break;
}
+#endif
default:
-#ifdef DIAGNOSTIC
+#ifdef DEBUG
printf("in6_gif_output: warning: unknown family %d passed\n",
family);
#endif
m_freem(m);
return EAFNOSUPPORT;
}
-
+
/* prepend new IP header */
M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
if (m && m->m_len < sizeof(struct ip6_hdr))
@@ -134,7 +146,8 @@ in6_gif_output(ifp, family, m, rt)
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_flow = 0;
- ip6->ip6_vfc = IPV6_VERSION;
+ ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6->ip6_vfc |= IPV6_VERSION;
ip6->ip6_plen = htons((u_short)m->m_pkthdr.len);
ip6->ip6_nxt = proto;
ip6->ip6_hlim = ip6_gif_hlim;
@@ -144,6 +157,10 @@ in6_gif_output(ifp, family, m, rt)
if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
ip6->ip6_dst = sin6_dst->sin6_addr;
else if (rt) {
+ if (family != AF_INET6) {
+ m_freem(m);
+ return EINVAL; /*XXX*/
+ }
ip6->ip6_dst = ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr;
} else {
m_freem(m);
@@ -175,6 +192,9 @@ in6_gif_output(ifp, family, m, rt)
RTFREE(sc->gif_ro6.ro_rt);
sc->gif_ro6.ro_rt = NULL;
}
+#if 0
+ sc->gif_if.if_mtu = GIF_MTU;
+#endif
}
if (sc->gif_ro6.ro_rt == NULL) {
@@ -183,9 +203,28 @@ in6_gif_output(ifp, family, m, rt)
m_freem(m);
return ENETUNREACH;
}
- }
+ /* if it constitutes infinite encapsulation, punt. */
+ if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
+ m_freem(m);
+ return ENETUNREACH; /*XXX*/
+ }
+#if 0
+ ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu
+ - sizeof(struct ip6_hdr);
+#endif
+ }
+
+#ifdef IPV6_MINMTU
+ /*
+ * 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.
+ */
+ return(ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL));
+#else
return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL));
+#endif
}
int in6_gif_input(mp, offp, proto)
@@ -193,44 +232,21 @@ int in6_gif_input(mp, offp, proto)
int *offp, proto;
{
struct mbuf *m = *mp;
- struct gif_softc *sc;
struct ifnet *gifp = NULL;
struct ip6_hdr *ip6;
- int i;
int af = 0;
u_int32_t otos;
ip6 = mtod(m, struct ip6_hdr *);
-#define satoin6(sa) (((struct sockaddr_in6 *)(sa))->sin6_addr)
- for (i = 0, sc = gif; i < ngif; i++, sc++) {
- if (sc->gif_psrc == NULL ||
- sc->gif_pdst == NULL ||
- sc->gif_psrc->sa_family != AF_INET6 ||
- sc->gif_pdst->sa_family != AF_INET6) {
- continue;
- }
- if ((sc->gif_if.if_flags & IFF_UP) == 0)
- continue;
- if ((sc->gif_if.if_flags & IFF_LINK0) &&
- IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) &&
- IN6_IS_ADDR_UNSPECIFIED(&satoin6(sc->gif_pdst))) {
- gifp = &sc->gif_if;
- continue;
- }
- if (IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) &&
- IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_pdst), &ip6->ip6_src)) {
- gifp = &sc->gif_if;
- break;
- }
- }
+ gifp = (struct ifnet *)encap_getarg(m);
- if (gifp == NULL) {
+ if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
m_freem(m);
ip6stat.ip6s_nogif++;
return IPPROTO_DONE;
}
-
+
otos = ip6->ip6_flow;
m_adj(m, *offp);
@@ -253,6 +269,7 @@ int in6_gif_input(mp, offp, proto)
break;
}
#endif /* INET */
+#ifdef INET6
case IPPROTO_IPV6:
{
struct ip6_hdr *ip6;
@@ -267,12 +284,76 @@ int in6_gif_input(mp, offp, proto)
ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow);
break;
}
+#endif
default:
ip6stat.ip6s_nogif++;
m_freem(m);
return IPPROTO_DONE;
}
-
+
gif_input(m, af, gifp);
return IPPROTO_DONE;
}
+
+/*
+ * we know that we are in IFF_UP, outer address available, and outer family
+ * matched the physical addr family. see gif_encapcheck().
+ */
+int
+gif_encapcheck6(m, off, proto, arg)
+ const struct mbuf *m;
+ int off;
+ int proto;
+ void *arg;
+{
+ struct ip6_hdr ip6;
+ struct gif_softc *sc;
+ struct sockaddr_in6 *src, *dst;
+ int addrmatch;
+
+ /* sanity check done in caller */
+ sc = (struct gif_softc *)arg;
+ src = (struct sockaddr_in6 *)sc->gif_psrc;
+ dst = (struct sockaddr_in6 *)sc->gif_pdst;
+
+ /* LINTED const cast */
+ m_copydata((struct mbuf *)m, 0, sizeof(ip6), (caddr_t)&ip6);
+
+ /* check for address match */
+ addrmatch = 0;
+ if (IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6.ip6_dst))
+ addrmatch |= 1;
+ if (IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6.ip6_src))
+ addrmatch |= 2;
+ else if ((sc->gif_if.if_flags & IFF_LINK0) != 0 &&
+ IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) {
+ addrmatch |= 2; /* we accept any source */
+ }
+ if (addrmatch != 3)
+ return 0;
+
+ /* martian filters on outer source - done in ip6_input */
+
+ /* ingress filters on outer source */
+ if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) {
+ struct sockaddr_in6 sin6;
+ struct rtentry *rt;
+
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_addr = ip6.ip6_src;
+ /* XXX scopeid */
+ rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
+ if (!rt)
+ return 0;
+ if (rt->rt_ifp != m->m_pkthdr.rcvif) {
+ rtfree(rt);
+ return 0;
+ }
+ rtfree(rt);
+ }
+
+ /* prioritize: IFF_LINK0 mode is less preferred */
+ return (sc->gif_if.if_flags & IFF_LINK0) ? 128 : 128 * 2;
+}
OpenPOWER on IntegriCloud