]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet/ip_ecn.c
xnu-3248.20.55.tar.gz
[apple/xnu.git] / bsd / netinet / ip_ecn.c
index 28a5589612c2c021945b3c74344a8991662756de..70ce0cfb8576bf363bf2459afd5335cec1d71b68 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000,2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2007, 2015 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -91,11 +91,10 @@ ip_ecn_ingress(mode, outer, inner)
 
        *outer = *inner;
        switch (mode) {
-       case ECN_ALLOWED:               /* ECN allowed */
-               *outer &= ~IPTOS_CE;
+       case ECN_NORMAL:                /* ECN normal mode, copy flags */
                break;
-       case ECN_FORBIDDEN:             /* ECN forbidden */
-               *outer &= ~(IPTOS_ECT | IPTOS_CE);
+       case ECN_COMPATIBILITY:         /* ECN compatibility mode */
+               *outer &= ~IPTOS_ECN_MASK;
                break;
        case ECN_NOCARE:        /* no consideration to ECN */
                break;
@@ -105,7 +104,7 @@ ip_ecn_ingress(mode, outer, inner)
 /*
  * modify inner ECN (TOS) field on egress operation (tunnel decapsulation).
  */
-void
+int
 ip_ecn_egress(mode, outer, inner)
        int mode;
        const u_int8_t *outer;
@@ -115,14 +114,21 @@ ip_ecn_egress(mode, outer, inner)
                panic("NULL pointer passed to ip_ecn_egress");
 
        switch (mode) {
-       case ECN_ALLOWED:
-               if (*outer & IPTOS_CE)
-                       *inner |= IPTOS_CE;
+       /* Process ECN for both normal and compatibility modes */
+       case ECN_NORMAL:
+       case ECN_COMPATIBILITY:
+               if (((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_CE) &&
+                   ((*inner & IPTOS_ECN_MASK) != IPTOS_ECN_NOTECT)) {
+                       *inner |= IPTOS_ECN_CE;
+               } else if ((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_ECT1 &&
+                                  (*inner & IPTOS_ECN_MASK) == IPTOS_ECN_ECT0) {
+                       *inner = *outer;
+               }
                break;
-       case ECN_FORBIDDEN:             /* ECN forbidden */
        case ECN_NOCARE:        /* no consideration to ECN */
                break;
        }
+       return (1);
 }
 
 #if INET6
@@ -143,7 +149,7 @@ ip6_ecn_ingress(mode, outer, inner)
        *outer |= htonl((u_int32_t)outer8 << 20);
 }
 
-void
+int
 ip6_ecn_egress(mode, outer, inner)
        int mode;
        const u_int32_t *outer;
@@ -156,8 +162,95 @@ ip6_ecn_egress(mode, outer, inner)
 
        outer8 = (ntohl(*outer) >> 20) & 0xff;
        inner8 = (ntohl(*inner) >> 20) & 0xff;
-       ip_ecn_egress(mode, &outer8, &inner8);
+       if (ip_ecn_egress(mode, &outer8, &inner8) == 0) {
+               return (0);
+       }
+       *inner &= ~htonl(0xff << 20);
+       *inner |= htonl((u_int32_t)inner8 << 20);
+       return (1);
+}
+
+/*
+ * Modify outer IPv6 ECN (Traffic Class) field according to inner IPv4 TOS field
+ * on ingress operation (tunnel encapsulation).
+ */
+void
+ip46_ecn_ingress(mode, outer, tos)
+       int mode;
+       u_int32_t *outer;
+       const u_int8_t *tos;
+{
+       u_int8_t outer8;
+
+       if (!outer || !tos)
+               panic("NULL pointer passed to ip46_ecn_ingress");
+
+       ip_ecn_ingress(mode, &outer8, tos);
+       *outer &= ~htonl(0xff << 20);
+       *outer |= htonl((u_int32_t)outer8 << 20);
+}
+
+/*
+ * Modify inner IPv4 ECN (TOS) field according to output IPv6 ECN (Traffic Class)
+ * on egress operation (tunnel decapsulation).
+ */
+int
+ip46_ecn_egress(mode, outer, tos)
+       int mode;
+       const u_int32_t *outer;
+       u_int8_t *tos;
+{
+       u_int8_t outer8;
+
+       if (!outer || !tos)
+               panic("NULL pointer passed to ip46_ecn_egress");
+
+       outer8 = (ntohl(*outer) >> 20) & 0xff;
+       return ip_ecn_egress(mode, &outer8, tos);
+}
+
+/*
+ * Modify outer IPv4 TOS field according to inner IPv6 ECN (Traffic Class)
+ * on ingress operation (tunnel encapsulation).
+ */
+void
+ip64_ecn_ingress(mode, outer, inner)
+       int mode;
+       u_int8_t *outer;
+       const u_int32_t *inner;
+{
+       u_int8_t inner8;
+
+       if (!outer || ! inner)
+               panic("NULL pointer passed to ip64_ecn_ingress");
+
+       inner8 = (ntohl(*inner) >> 20) & 0xff;
+       ip_ecn_ingress(mode, outer, &inner8);
+}
+
+/*
+ * Modify inner IPv6 ECN (Traffic Class) according to outer IPv4 TOS field
+ * on egress operation (tunnel decapsulation).
+ */
+int
+ip64_ecn_egress(mode, outer, inner)
+       int mode;
+       const u_int8_t *outer;
+       u_int32_t *inner;
+{
+       u_int8_t inner8;
+
+       if (!outer || !inner)
+               panic("NULL pointer passed to ip64_ecn_egress");
+
+       inner8 = (ntohl(*inner) >> 20) & 0xff;
+       if (ip_ecn_egress(mode, outer, &inner8) == 0) {
+               return (0);
+       }
+
        *inner &= ~htonl(0xff << 20);
        *inner |= htonl((u_int32_t)inner8 << 20);
+       return (1);
 }
+
 #endif