Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet6/in6_gif.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet6/in6_gif.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.13 retrieving revision 1.14 diff -u -p -r1.13 -r1.14 --- src/sys/netinet6/in6_gif.c 2000/03/01 12:49:45 1.13 +++ src/sys/netinet6/in6_gif.c 2000/04/19 06:30:56 1.14 @@ -1,9 +1,10 @@ -/* $NetBSD: in6_gif.c,v 1.13 2000/03/01 12:49:45 itojun Exp $ */ +/* $NetBSD: in6_gif.c,v 1.14 2000/04/19 06:30:56 itojun Exp $ */ +/* $KAME: in6_gif.c,v 1.34 2000/04/19 04:51:58 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -15,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -33,7 +34,9 @@ * in6_gif.c */ +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) #include "opt_inet.h" +#endif #include #include @@ -41,8 +44,13 @@ #include #include #include +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) #include -#include +#endif + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#endif #include #include @@ -52,10 +60,12 @@ #ifdef INET #include #endif +#include #ifdef INET6 #include #include #include +#include #endif #include @@ -194,13 +204,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) @@ -208,44 +233,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); @@ -293,3 +295,70 @@ int in6_gif_input(mp, offp, proto) 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 */ +#ifdef __FreeBSD__ + rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); +#else + rt = rtalloc1((struct sockaddr *)&sin6, 0); +#endif + 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; +}