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 <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 #include "opt_inet.h" 43 #include "opt_inet6.h" 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/mbuf.h> 48 #include <sys/errno.h> 49 50 #include <netinet/in.h> 51 #include <netinet/in_systm.h> 52 #include <netinet/ip.h> 53 #ifdef INET6 54 #include <netinet/ip6.h> 55 #endif 56 57 #include <netinet/ip_ecn.h> 58 #ifdef INET6 59 #include <netinet6/ip6_ecn.h> 60 #endif 61 62 /* 63 * ECN and TOS (or TCLASS) processing rules at tunnel encapsulation and 64 * decapsulation from RFC3168: 65 * 66 * Outer Hdr at Inner Hdr at 67 * Encapsulator Decapsulator 68 * Header fields: -------------------- ------------ 69 * DS Field copied from inner hdr no change 70 * ECN Field constructed by (I) constructed by (E) 71 * 72 * ECN_ALLOWED (full functionality): 73 * (I) if the ECN field in the inner header is set to CE, then set the 74 * ECN field in the outer header to ECT(0). 75 * otherwise, copy the ECN field to the outer header. 76 * 77 * (E) if the ECN field in the outer header is set to CE and the ECN 78 * field of the inner header is not-ECT, drop the packet. 79 * if the ECN field in the inner header is set to ECT(0) or ECT(1) 80 * and the ECN field in the outer header is set to CE, then copy CE to 81 * the inner header. otherwise, make no change to the inner header. 82 * 83 * ECN_FORBIDDEN (limited functionality): 84 * (I) set the ECN field to not-ECT in the outer header. 85 * 86 * (E) if the ECN field in the outer header is set to CE, drop the packet. 87 * otherwise, make no change to the ECN field in the inner header. 88 * 89 * the drop rule is for backward compatibility and protection against 90 * erasure of CE. 91 */ 92 93 /* 94 * modify outer ECN (TOS) field on ingress operation (tunnel encapsulation). 95 */ 96 void 97 ip_ecn_ingress(int mode, u_int8_t *outer, const u_int8_t *inner) 98 { 99 100 if (!outer || !inner) 101 panic("NULL pointer passed to ip_ecn_ingress"); 102 103 *outer = *inner; 104 switch (mode) { 105 case ECN_ALLOWED: /* ECN allowed */ 106 /* 107 * full-functionality: if the inner is CE, set ECT(0) 108 * to the outer. otherwise, copy the ECN field. 109 */ 110 if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_CE) 111 *outer &= ~IPTOS_ECN_ECT1; 112 break; 113 case ECN_FORBIDDEN: /* ECN forbidden */ 114 /* 115 * limited-functionality: set not-ECT to the outer 116 */ 117 *outer &= ~IPTOS_ECN_MASK; 118 break; 119 case ECN_NOCARE: /* no consideration to ECN */ 120 break; 121 } 122 } 123 124 /* 125 * modify inner ECN (TOS) field on egress operation (tunnel decapsulation). 126 * the caller should drop the packet if the return value is 0. 127 */ 128 int 129 ip_ecn_egress(int mode, const u_int8_t *outer, u_int8_t *inner) 130 { 131 132 if (!outer || !inner) 133 panic("NULL pointer passed to ip_ecn_egress"); 134 135 switch (mode) { 136 case ECN_ALLOWED: 137 /* 138 * full-functionality: if the outer is CE and the inner is 139 * not-ECT, should drop it. otherwise, copy CE. 140 */ 141 if ((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_CE) { 142 if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT) 143 return (0); 144 *inner |= IPTOS_ECN_CE; 145 } 146 break; 147 case ECN_FORBIDDEN: /* ECN forbidden */ 148 /* 149 * limited-functionality: if the outer is CE, should drop it. 150 * otherwise, leave the inner. 151 */ 152 if ((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_CE) 153 return (0); 154 break; 155 case ECN_NOCARE: /* no consideration to ECN */ 156 break; 157 } 158 return (1); 159 } 160 161 #ifdef INET6 162 void 163 ip6_ecn_ingress(int mode, u_int32_t *outer, const u_int32_t *inner) 164 { 165 u_int8_t outer8, inner8; 166 167 if (!outer || !inner) 168 panic("NULL pointer passed to ip6_ecn_ingress"); 169 170 inner8 = (ntohl(*inner) >> 20) & 0xff; 171 ip_ecn_ingress(mode, &outer8, &inner8); 172 *outer &= ~htonl(0xff << 20); 173 *outer |= htonl((u_int32_t)outer8 << 20); 174 } 175 176 int 177 ip6_ecn_egress(int mode, const u_int32_t *outer, u_int32_t *inner) 178 { 179 u_int8_t outer8, inner8, oinner8; 180 181 if (!outer || !inner) 182 panic("NULL pointer passed to ip6_ecn_egress"); 183 184 outer8 = (ntohl(*outer) >> 20) & 0xff; 185 inner8 = oinner8 = (ntohl(*inner) >> 20) & 0xff; 186 if (ip_ecn_egress(mode, &outer8, &inner8) == 0) 187 return (0); 188 if (inner8 != oinner8) { 189 *inner &= ~htonl(0xff << 20); 190 *inner |= htonl((u_int32_t)inner8 << 20); 191 } 192 return (1); 193 } 194 #endif 195