]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet6/in6_gif.c
xnu-3789.70.16.tar.gz
[apple/xnu.git] / bsd / netinet6 / in6_gif.c
index 6142092c518d1adb8ac279c08a8a5587f0934699..89037d5b1e5df832af9bd99d724c739b0c57836f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -162,7 +162,7 @@ in6_gif_output(
        }
 
        /* prepend new IP header */
-       M_PREPEND(m, sizeof (struct ip6_hdr), M_DONTWAIT);
+       M_PREPEND(m, sizeof (struct ip6_hdr), M_DONTWAIT, 1);
        if (m && mbuf_len(m) < sizeof (struct ip6_hdr))
                m = m_pullup(m, sizeof (struct ip6_hdr));
        if (m == NULL) {
@@ -185,7 +185,7 @@ in6_gif_output(
                m_freem(m);
                return (ENETUNREACH);
        }
-       ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE,
+       ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_NORMAL : ECN_NOCARE,
            &otos, &itos);
        ip6->ip6_flow &= ~htonl(0xff << 20);
        ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
@@ -245,6 +245,7 @@ in6_gif_input(struct mbuf **mp, int *offp, int proto)
        struct ip6_hdr *ip6;
        int af = 0;
        u_int32_t otos;
+       int egress_success = 0;
 
        ip6 = mtod(m, struct ip6_hdr *);
 
@@ -264,7 +265,9 @@ in6_gif_input(struct mbuf **mp, int *offp, int proto)
        case IPPROTO_IPV4:
            {
                struct ip *ip;
-               u_int8_t otos8;
+               u_int8_t otos8, old_tos;
+               int sum;
+
                af = AF_INET;
                otos8 = (ntohl(otos) >> 20) & 0xff;
                if (mbuf_len(m) < sizeof (*ip)) {
@@ -273,10 +276,18 @@ in6_gif_input(struct mbuf **mp, int *offp, int proto)
                                return (IPPROTO_DONE);
                }
                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);
+               if (gifp->if_flags & IFF_LINK1) {
+                       old_tos = ip->ip_tos;
+                       egress_success = ip_ecn_egress(ECN_NORMAL, &otos8, &ip->ip_tos);
+                       if (old_tos != ip->ip_tos) {
+                           sum = ~ntohs(ip->ip_sum) & 0xffff;
+                           sum += (~old_tos & 0xffff) + ip->ip_tos;
+                           sum = (sum >> 16) + (sum & 0xffff);
+                           sum += (sum >> 16);  /* add carry */
+                           ip->ip_sum = htons(~sum & 0xffff);
+                       }
+               } else
+                       egress_success = ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos);
                break;
            }
 #endif /* INET */
@@ -291,9 +302,9 @@ in6_gif_input(struct mbuf **mp, int *offp, int proto)
                }
                ip6 = mtod(m, struct ip6_hdr *);
                if (gifp->if_flags & IFF_LINK1)
-                       ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow);
+                       egress_success = ip6_ecn_egress(ECN_NORMAL, &otos, &ip6->ip6_flow);
                else
-                       ip6_ecn_egress(ECN_NOCARE, &otos, &ip6->ip6_flow);
+                       egress_success = ip6_ecn_egress(ECN_NOCARE, &otos, &ip6->ip6_flow);
                break;
            }
 #endif
@@ -303,6 +314,12 @@ in6_gif_input(struct mbuf **mp, int *offp, int proto)
                return (IPPROTO_DONE);
        }
 
+       if (egress_success == 0) {
+               ip6stat.ip6s_nogif++;
+               m_freem(m);
+               return (IPPROTO_DONE);
+       }
+
        /* Replace the rcvif by gifp for ifnet_input to route it correctly */
        if (m->m_pkthdr.rcvif)
                m->m_pkthdr.rcvif = gifp;