]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet6/route6.c
xnu-1228.tar.gz
[apple/xnu.git] / bsd / netinet6 / route6.c
index 7867df06f7527aa652f875dc9d2e5f6fe7579934..36617f2d0076b2a2491d1872b2605d12442e2e13 100644 (file)
 #include <sys/mbuf.h>
 #include <sys/socket.h>
 #include <sys/queue.h>
+#include <string.h>
 
 #include <net/if.h>
+#include <net/route.h>
 
 #include <netinet/in.h>
 #include <netinet6/in6_var.h>
 
 #include <netinet/icmp6.h>
 
-static int ip6_rthdr0 __P((struct mbuf *, struct ip6_hdr *,
-    struct ip6_rthdr0 *));
+#if IP6_RTHDR0_ALLOWED
+static int ip6_rthdr0(struct mbuf *, struct ip6_hdr *,
+    struct ip6_rthdr0 *);
+#endif /* IP6_RTHDR0_ALLOWED */
 
 int
-route6_input(mp, offp, proto)
-       struct mbuf **mp;
-       int *offp, proto;       /* proto is unused */
+route6_input(struct mbuf **mp, int *offp)
 {
        struct ip6_hdr *ip6;
        struct mbuf *m = *mp;
        struct ip6_rthdr *rh;
        int off = *offp, rhlen;
-       struct mbuf *n;
+       struct ip6aux *ip6a;
 
-       n = ip6_findaux(m);
-       if (n) {
-               struct ip6aux *ip6a = mtod(n, struct ip6aux *);
+       ip6a = ip6_findaux(m);
+       if (ip6a) {
                /* XXX reject home-address option before rthdr */
                if (ip6a->ip6a_flags & IP6A_SWAP) {
                        ip6stat.ip6s_badoptions++;
@@ -70,7 +71,7 @@ route6_input(mp, offp, proto)
        }
 
 #ifndef PULLDOWN_TEST
-       IP6_EXTHDR_CHECK(m, off, sizeof(*rh), IPPROTO_DONE);
+       IP6_EXTHDR_CHECK(m, off, sizeof(*rh), return IPPROTO_DONE);
        ip6 = mtod(m, struct ip6_hdr *);
        rh = (struct ip6_rthdr *)((caddr_t)ip6 + off);
 #else
@@ -83,6 +84,7 @@ route6_input(mp, offp, proto)
 #endif
 
        switch (rh->ip6r_type) {
+#if IP6_RTHDR0_ALLOWED
        case IPV6_RTHDR_TYPE_0:
                rhlen = (rh->ip6r_len + 1) << 3;
 #ifndef PULLDOWN_TEST
@@ -91,7 +93,7 @@ route6_input(mp, offp, proto)
                 * due to IP6_EXTHDR_CHECK assumption, we cannot handle
                 * very big routing header (max rhlen == 2048).
                 */
-               IP6_EXTHDR_CHECK(m, off, rhlen, IPPROTO_DONE);
+               IP6_EXTHDR_CHECK(m, off, rhlen, return IPPROTO_DONE);
 #else
                /*
                 * note on option length:
@@ -110,6 +112,7 @@ route6_input(mp, offp, proto)
                if (ip6_rthdr0(m, ip6, (struct ip6_rthdr0 *)rh))
                        return(IPPROTO_DONE);
                break;
+#endif /* IP6_RTHDR0_ALLOWED */
        default:
                /* unknown routing type */
                if (rh->ip6r_segleft == 0) {
@@ -126,6 +129,7 @@ route6_input(mp, offp, proto)
        return(rh->ip6r_nxt);
 }
 
+#if IP6_RTHDR0_ALLOWED
 /*
  * Type0 routing header processing
  *
@@ -140,6 +144,7 @@ ip6_rthdr0(m, ip6, rh0)
 {
        int addrs, index;
        struct in6_addr *nextaddr, tmpaddr;
+       struct route_in6 ip6forward_rt;
 
        if (rh0->ip6r0_segleft == 0)
                return(0);
@@ -205,14 +210,31 @@ ip6_rthdr0(m, ip6, rh0)
        if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
                ip6->ip6_dst.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
 
+       /*
+        * Don't use the globally cached route to forward packet having
+        * Type 0 routing header(s); instead, do an explicit lookup using
+        * a local route entry variable, in case the next address in the
+        * packet is bogus (which would otherwise unnecessarily invalidate
+        * the globally cached route).
+        */
+       bzero(&ip6forward_rt, sizeof (ip6forward_rt));
+
 #if COMPAT_RFC1883
        if (rh0->ip6r0_slmap[index / 8] & (1 << (7 - (index % 8))))
-               ip6_forward(m, IPV6_SRCRT_NEIGHBOR);
+               ip6_forward(m, &ip6forward_rt, IPV6_SRCRT_NEIGHBOR, 0);
        else
-               ip6_forward(m, IPV6_SRCRT_NOTNEIGHBOR);
+               ip6_forward(m, &ip6forward_rt, IPV6_SRCRT_NOTNEIGHBOR, 0);
 #else
-       ip6_forward(m, 1);
+       ip6_forward(m, &ip6forward_rt, 1, 0);
 #endif
 
+       /* Release reference to the looked up route */
+       if (ip6forward_rt.ro_rt != NULL) {
+               rtfree(ip6forward_rt.ro_rt);
+               ip6forward_rt.ro_rt = NULL;
+       }
+
        return(-1);                     /* m would be freed in ip6_forward() */
 }
+#endif /* IP6_RTHDR0_ALLOWED */
+