]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet6/in6_gif.c
xnu-517.11.1.tar.gz
[apple/xnu.git] / bsd / netinet6 / in6_gif.c
index c756948dc0931496996f50aef9728a6b113c24c4..2886c784b5ac31bdbb61495c0435adf620db08e4 100644 (file)
@@ -1,4 +1,5 @@
-/*     $KAME: in6_gif.c,v 1.27 2000/03/25 07:23:43 sumikawa Exp $      */
+/*     $FreeBSD: src/sys/netinet6/in6_gif.c,v 1.2.2.3 2001/07/03 11:01:52 ume Exp $    */
+/*     $KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $        */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * SUCH DAMAGE.
  */
 
-/*
- * in6_gif.c
- */
-
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
-#include "opt_inet.h"
-#endif
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -43,9 +37,9 @@
 #include <sys/sockio.h>
 #include <sys/mbuf.h>
 #include <sys/errno.h>
-#if !defined(__FreeBSD__) || __FreeBSD__ < 3
-#include <sys/ioctl.h>
-#endif
+#include <sys/queue.h>
+#include <sys/syslog.h>
+
 #include <sys/malloc.h>
 #include <sys/protosw.h>
 
 #include <netinet6/ip6_var.h>
 #include <netinet6/in6_gif.h>
 #include <netinet6/in6_var.h>
-#include <netinet6/ip6protosw.h>
 #endif
 #include <netinet/ip_ecn.h>
+#if INET6
+#include <netinet6/ip6_ecn.h>
+#endif
 
 #include <net/if_gif.h>
 
 #include <net/net_osdep.h>
 
-#if INET6
-extern struct ip6protosw in6_gif_protosw;
-#endif
-
 int
 in6_gif_output(ifp, family, m, rt)
        struct ifnet *ifp;
@@ -155,34 +147,19 @@ in6_gif_output(ifp, family, m, rt)
        ip6->ip6_nxt    = proto;
        ip6->ip6_hlim   = ip6_gif_hlim;
        ip6->ip6_src    = sin6_src->sin6_addr;
-       if (ifp->if_flags & IFF_LINK0) {
-               /* multi-destination mode */
-               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);
-                       return ENETUNREACH;
-               }
-       } else {
-               /* bidirectional configured tunnel mode */
-               if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
-                       ip6->ip6_dst = sin6_dst->sin6_addr;
-               else  {
-                       m_freem(m);
-                       return ENETUNREACH;
-               }
+       /* bidirectional configured tunnel mode */
+       if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
+               ip6->ip6_dst = sin6_dst->sin6_addr;
+       else  {
+               m_freem(m);
+               return ENETUNREACH;
        }
-       if (ifp->if_flags & IFF_LINK1) {
-               otos = 0;
+       if (ifp->if_flags & IFF_LINK1)
                ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
-               ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
-       }
+       else
+               ip_ecn_ingress(ECN_NOCARE, &otos, &itos);
+       ip6->ip6_flow &= ~ntohl(0xff00000);
+       ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
 
        if (dst->sin6_family != sin6_dst->sin6_family ||
             !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
@@ -192,7 +169,7 @@ in6_gif_output(ifp, family, m, rt)
                dst->sin6_len = sizeof(struct sockaddr_in6);
                dst->sin6_addr = sin6_dst->sin6_addr;
                if (sc->gif_ro6.ro_rt) {
-                       RTFREE(sc->gif_ro6.ro_rt);
+                       rtfree(sc->gif_ro6.ro_rt);
                        sc->gif_ro6.ro_rt = NULL;
                }
 #if 0
@@ -206,72 +183,52 @@ 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
        }
        
+#if 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)
+int in6_gif_input(mp, offp)
        struct mbuf **mp;
-       int *offp, proto;
+       int *offp;
 {
        struct mbuf *m = *mp;
-#if 0
-       struct gif_softc *sc;
-#endif
        struct ifnet *gifp = NULL;
        struct ip6_hdr *ip6;
-#if 0
-       int i;
-#endif
        int af = 0;
        u_int32_t otos;
+       u_int8_t proto;
 
        ip6 = mtod(m, struct ip6_hdr *);
 
-#if 0
-#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;
-               }
-       }
-#else
        gifp = (struct ifnet *)encap_getarg(m);
-#endif
 
-       if (gifp == NULL) {
-               m_freem(m);
-               ip6stat.ip6s_nogif++;
-               return IPPROTO_DONE;
-       }
-
-       if ((gifp->if_flags & IFF_UP) == 0) {
+       if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
                m_freem(m);
                ip6stat.ip6s_nogif++;
                return IPPROTO_DONE;
        }
 
+       proto = ip6->ip6_nxt;
        otos = ip6->ip6_flow;
        m_adj(m, *offp);
 
@@ -291,6 +248,8 @@ int in6_gif_input(mp, offp, proto)
                ip = mtod(m, struct ip *);
                if (gifp->if_flags & IFF_LINK1)
                        ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos);
+               else
+                       ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos);
                break;
            }
 #endif /* INET */
@@ -307,6 +266,8 @@ int in6_gif_input(mp, offp, proto)
                ip6 = mtod(m, struct ip6_hdr *);
                if (gifp->if_flags & IFF_LINK1)
                        ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow);
+               else
+                       ip6_ecn_egress(ECN_NOCARE, &otos, &ip6->ip6_flow);
                break;
            }
 #endif
@@ -316,144 +277,87 @@ int in6_gif_input(mp, offp, proto)
                return IPPROTO_DONE;
        }
                
-       gif_input(m, af, gifp);
+       dlil_input(gifp, m, m);
        return IPPROTO_DONE;
 }
 
-int
-in6_gif_ioctl(ifp, cmd, data)
+/*
+ * validate outer address.
+ */
+static int
+gif_validate6(ip6, sc, ifp)
+       const struct ip6_hdr *ip6;
+       struct gif_softc *sc;
        struct ifnet *ifp;
-#if defined(__FreeBSD__) && __FreeBSD__ < 3
-       int cmd;
-#else
-       u_long cmd;
-#endif
-       caddr_t data;
 {
-       struct gif_softc *sc  = (struct gif_softc*)ifp;
-       struct ifreq     *ifr = (struct ifreq*)data;
-       int error = 0, size;
-       struct sockaddr *sa, *dst, *src;
-       const struct encaptab *p;
-       struct sockaddr_in6 smask6, dmask6;
-               
-       switch (cmd) {
-       case SIOCSIFFLAGS:
-               /*
-                * whenever we change our idea about multi-destination mode
-                * we need to update encap attachment.
-                */
-               if (((ifp->if_flags ^ sc->gif_oflags) & IFF_LINK0) == 0)
-                       break;
-               if (sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
-                   sc->gif_psrc->sa_family != sc->gif_pdst->sa_family)
-                       break;
-               bzero(&smask6, sizeof(smask6));
-               smask6.sin6_addr.s6_addr32[0] = ~0;
-               smask6.sin6_addr.s6_addr32[1] = ~0;
-               smask6.sin6_addr.s6_addr32[2] = ~0;
-               smask6.sin6_addr.s6_addr32[3] = ~0;
-#if 0  /* we'll need to do this soon */
-               smask6.sin6_scope_id = ~0;
+       struct sockaddr_in6 *src, *dst;
+
+       src = (struct sockaddr_in6 *)sc->gif_psrc;
+       dst = (struct sockaddr_in6 *)sc->gif_pdst;
+
+       /*
+        * Check for address match.  Note that the check is for an incoming
+        * packet.  We should compare the *source* address in our configuration
+        * and the *destination* address of the packet, and vice versa.
+        */
+       if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
+           !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
+               return 0;
+
+       /* martian filters on outer source - done in ip6_input */
+
+       /* ingress filters on outer source */
+       if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {
+               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;
+#ifndef SCOPEDROUTING
+               sin6.sin6_scope_id = 0; /* XXX */
 #endif
-               dmask6 = smask6;
-               if ((ifp->if_flags & IFF_LINK0) == 0 &&
-                   IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)dst)->sin6_addr)) {
-                       bzero(&dmask6, sizeof(dmask6));
-#if 0  /* we'll need to do this soon */
-                       dmask6.sin6_scope_id = ~0;
-#endif
-               }
-               p = encap_attach(sc->gif_psrc->sa_family, -1, sc->gif_psrc,
-                       (struct sockaddr *)&smask6, sc->gif_pdst,
-                       (struct sockaddr *)&dmask6,
-                       (struct protosw *)&in6_gif_protosw, &sc->gif_if);
-               if (p == NULL) {
-                       error = EINVAL;
-                       goto bad;
-               }
-               if (sc->encap_cookie != NULL)
-                       (void)encap_detach(sc->encap_cookie);
-               sc->encap_cookie = p;
-               sc->gif_oflags = ifp->if_flags;
-
-               break;
 
-#if INET6
-       case SIOCSIFPHYADDR_IN6:
-#endif
-               switch (ifr->ifr_addr.sa_family) {
-#if INET6
-               case AF_INET6:
-                       src = (struct sockaddr *)
-                               &(((struct in6_aliasreq *)data)->ifra_addr);
-                       dst = (struct sockaddr *)
-                               &(((struct in6_aliasreq *)data)->ifra_dstaddr);
-
-                       bzero(&smask6, sizeof(smask6));
-                       smask6.sin6_addr.s6_addr32[0] = ~0;
-                       smask6.sin6_addr.s6_addr32[1] = ~0;
-                       smask6.sin6_addr.s6_addr32[2] = ~0;
-                       smask6.sin6_addr.s6_addr32[3] = ~0;
-#if 0  /* we'll need to do this soon */
-                       smask6.sin6_scope_id = ~0;
-#endif
-                       dmask6 = smask6;
-                       if ((ifp->if_flags & IFF_LINK0) == 0 &&
-                           IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)dst)->sin6_addr)) {
-                               bzero(&dmask6, sizeof(dmask6));
-#if 0  /* we'll need to do this soon */
-                               dmask6.sin6_scope_id = ~0;
+               rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
+               if (!rt || rt->rt_ifp != ifp) {
+#if 0
+                       log(LOG_WARNING, "%s: packet from %s dropped "
+                           "due to ingress filter\n", if_name(&sc->gif_if),
+                           ip6_sprintf(&sin6.sin6_addr));
 #endif
-                       }
-                       size = sizeof(struct sockaddr_in6);
-                       break;
-#endif /* INET6 */
-               default:
-                       error = EAFNOSUPPORT;
-                       goto bad;
+                       if (rt)
+                               rtfree(rt);
+                       return 0;
                }
+               rtfree(rt);
+       }
 
-               if (sc->encap_cookie != NULL)
-                       (void)encap_detach(sc->encap_cookie);
-               if (sc->gif_psrc != NULL) {
-                       _FREE((caddr_t)sc->gif_psrc, M_IFADDR);
-                       sc->gif_psrc = NULL;
-               }
-               if (sc->gif_pdst != NULL) {
-                       _FREE((caddr_t)sc->gif_pdst, M_IFADDR);
-                       sc->gif_pdst = NULL;
-               }
+       return 128 * 2;
+}
 
-               p = encap_attach(ifr->ifr_addr.sa_family, -1, src,
-                       (struct sockaddr *)&smask6, dst,
-                       (struct sockaddr *)&dmask6,
-                       (struct protosw *)&in6_gif_protosw, &sc->gif_if);
-               if (p == NULL) {
-                       error = EINVAL;
-                       goto bad;
-               }
-               sc->encap_cookie = p;
-               sc->gif_oflags = ifp->if_flags;
+/*
+ * we know that we are in IFF_UP, outer address available, and outer family
+ * matched the physical addr family.  see gif_encapcheck().
+ * sanity check for arg should have been done in the caller.
+ */
+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 ifnet *ifp;
 
-               sa = (struct sockaddr *)_MALLOC(size, M_IFADDR, M_WAITOK);
-               bcopy((caddr_t)src, (caddr_t)sa, size);
-               sc->gif_psrc = sa;
-               
-               sa = (struct sockaddr *)_MALLOC(size, M_IFADDR, M_WAITOK);
-               bcopy((caddr_t)dst, (caddr_t)sa, size);
-               sc->gif_pdst = sa;
-               
-               ifp->if_flags |= IFF_UP;
-               if_up(ifp);             /* send up RTM_IFINFO */
+       /* sanity check done in caller */
+       sc = (struct gif_softc *)arg;
 
-               error = 0;
-               break;
-       default:
-               error = EINVAL;
-               goto bad;
-       }
+       /* LINTED const cast */
+       m_copydata(m, 0, sizeof(ip6), (caddr_t)&ip6);
+       ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
 
- bad:
-       return error;
+       return gif_validate6(&ip6, sc, ifp);
 }