1 /* $KAME: ip_ecn.c,v 1.12 2002/01/07 11:34:47 kjc Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (C) 1999 WIDE Project. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 */ 34 /* 35 * ECN consideration on tunnel ingress/egress operation. 36 * http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt 37 */ 38 39 #include "opt_inet.h" 40 #include "opt_inet6.h" 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/mbuf.h> 45 #include <sys/errno.h> 46 47 #include <netinet/in.h> 48 #include <netinet/in_systm.h> 49 #include <netinet/ip.h> 50 #ifdef INET6 51 #include <netinet/ip6.h> 52 #endif 53 54 #include <netinet/ip_ecn.h> 55 #ifdef INET6 56 #include <netinet6/ip6_ecn.h> 57 #endif 58 59 /* 60 * ECN and TOS (or TCLASS) processing rules at tunnel encapsulation and 61 * decapsulation from RFC3168: 62 * 63 * Outer Hdr at Inner Hdr at 64 * Encapsulator Decapsulator 65 * Header fields: -------------------- ------------ 66 * DS Field copied from inner hdr no change 67 * ECN Field constructed by (I) constructed by (E) 68 * 69 * ECN_ALLOWED (full functionality): 70 * (I) if the ECN field in the inner header is set to CE, then set the 71 * ECN field in the outer header to ECT(0). 72 * otherwise, copy the ECN field to the outer header. 73 * 74 * (E) if the ECN field in the outer header is set to CE and the ECN 75 * field of the inner header is not-ECT, drop the packet. 76 * if the ECN field in the inner header is set to ECT(0) or ECT(1) 77 * and the ECN field in the outer header is set to CE, then copy CE to 78 * the inner header. otherwise, make no change to the inner header. 79 * 80 * ECN_FORBIDDEN (limited functionality): 81 * (I) set the ECN field to not-ECT in the outer header. 82 * 83 * (E) if the ECN field in the outer header is set to CE, drop the packet. 84 * otherwise, make no change to the ECN field in the inner header. 85 * 86 * the drop rule is for backward compatibility and protection against 87 * erasure of CE. 88 */ 89 90 /* 91 * modify outer ECN (TOS) field on ingress operation (tunnel encapsulation). 92 */ 93 void 94 ip_ecn_ingress(int mode, uint8_t *outer, const uint8_t *inner) 95 { 96 97 if (!outer || !inner) 98 panic("NULL pointer passed to ip_ecn_ingress"); 99 100 *outer = *inner; 101 switch (mode) { 102 case ECN_ALLOWED: /* ECN allowed */ 103 /* 104 * full-functionality: if the inner is CE, set ECT(0) 105 * to the outer. otherwise, copy the ECN field. 106 */ 107 if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_CE) 108 *outer &= ~IPTOS_ECN_ECT1; 109 break; 110 case ECN_FORBIDDEN: /* ECN forbidden */ 111 /* 112 * limited-functionality: set not-ECT to the outer 113 */ 114 *outer &= ~IPTOS_ECN_MASK; 115 break; 116 case ECN_NOCARE: /* no consideration to ECN */ 117 break; 118 } 119 } 120 121 /* 122 * modify inner ECN (TOS) field on egress operation (tunnel decapsulation). 123 * the caller should drop the packet if the return value is 0. 124 */ 125 int 126 ip_ecn_egress(int mode, const uint8_t *outer, uint8_t *inner) 127 { 128 129 if (!outer || !inner) 130 panic("NULL pointer passed to ip_ecn_egress"); 131 132 switch (mode) { 133 case ECN_ALLOWED: 134 /* 135 * full-functionality: if the outer is CE and the inner is 136 * not-ECT, should drop it. otherwise, copy CE. 137 */ 138 if ((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_CE) { 139 if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT) 140 return (0); 141 *inner |= IPTOS_ECN_CE; 142 } 143 break; 144 case ECN_FORBIDDEN: /* ECN forbidden */ 145 /* 146 * limited-functionality: if the outer is CE, should drop it. 147 * otherwise, leave the inner. 148 */ 149 if ((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_CE) 150 return (0); 151 break; 152 case ECN_NOCARE: /* no consideration to ECN */ 153 break; 154 } 155 return (1); 156 } 157 158 #ifdef INET6 159 void 160 ip6_ecn_ingress(int mode, uint32_t *outer, const uint32_t *inner) 161 { 162 uint8_t outer8, inner8; 163 164 if (!outer || !inner) 165 panic("NULL pointer passed to ip6_ecn_ingress"); 166 167 inner8 = (ntohl(*inner) >> 20) & 0xff; 168 ip_ecn_ingress(mode, &outer8, &inner8); 169 *outer &= ~htonl(0xff << 20); 170 *outer |= htonl((uint32_t)outer8 << 20); 171 } 172 173 int 174 ip6_ecn_egress(int mode, const uint32_t *outer, uint32_t *inner) 175 { 176 uint8_t outer8, inner8, oinner8; 177 178 if (!outer || !inner) 179 panic("NULL pointer passed to ip6_ecn_egress"); 180 181 outer8 = (ntohl(*outer) >> 20) & 0xff; 182 inner8 = oinner8 = (ntohl(*inner) >> 20) & 0xff; 183 if (ip_ecn_egress(mode, &outer8, &inner8) == 0) 184 return (0); 185 if (inner8 != oinner8) { 186 *inner &= ~htonl(0xff << 20); 187 *inner |= htonl((uint32_t)inner8 << 20); 188 } 189 return (1); 190 } 191 #endif 192