1/* 2 * Copyright (c) 2007-2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29/* 30 * Copyright (c) 1991-1997 Regents of the University of California. 31 * All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. All advertising materials mentioning features or use of this software 42 * must display the following acknowledgement: 43 * This product includes software developed by the Network Research 44 * Group at Lawrence Berkeley Laboratory. 45 * 4. Neither the name of the University nor of the Laboratory may be used 46 * to endorse or promote products derived from this software without 47 * specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 */ 61 62#include <sys/cdefs.h> 63#include <sys/param.h> 64#include <sys/mbuf.h> 65#include <sys/errno.h> 66#include <sys/random.h> 67#include <sys/kernel_types.h> 68#include <sys/sysctl.h> 69 70#include <net/if.h> 71#include <net/net_osdep.h> 72#include <net/classq/classq.h> 73 74#include <netinet/in.h> 75#include <netinet/in_systm.h> 76#include <netinet/ip.h> 77#if INET6 78#include <netinet/ip6.h> 79#endif 80#include <netinet/tcp.h> 81#include <netinet/udp.h> 82 83#include <libkern/libkern.h> 84 85#if PF_ECN 86/* 87 * read and write diffserv field in IPv4 or IPv6 header 88 */ 89u_int8_t 90read_dsfield(struct mbuf *m, struct pf_mtag *t) 91{ 92 struct mbuf *m0; 93 u_int8_t ds_field = 0; 94 95 if (t->pftag_hdr == NULL || 96 !(t->pftag_flags & (PF_TAG_HDR_INET|PF_TAG_HDR_INET6))) 97 return ((u_int8_t)0); 98 99 /* verify that hdr is within the mbuf data */ 100 for (m0 = m; m0 != NULL; m0 = m0->m_next) 101 if (((caddr_t)t->pftag_hdr >= m0->m_data) && 102 ((caddr_t)t->pftag_hdr < m0->m_data + m0->m_len)) 103 break; 104 if (m0 == NULL) { 105 /* ick, tag info is stale */ 106 printf("%s: can't locate header!\n", __func__); 107 return ((u_int8_t)0); 108 } 109 110 if (t->pftag_flags & PF_TAG_HDR_INET) { 111 struct ip *ip = (struct ip *)(void *)t->pftag_hdr; 112 113 if (((uintptr_t)ip + sizeof (*ip)) > 114 ((uintptr_t)mbuf_datastart(m0) + mbuf_maxlen(m0))) 115 return (0); /* out of bounds */ 116 117 if (ip->ip_v != 4) 118 return ((u_int8_t)0); /* version mismatch! */ 119 ds_field = ip->ip_tos; 120 } 121#if INET6 122 else if (t->pftag_flags & PF_TAG_HDR_INET6) { 123 struct ip6_hdr *ip6 = (struct ip6_hdr *)(void *)t->pftag_hdr; 124 u_int32_t flowlabel; 125 126 if (((uintptr_t)ip6 + sizeof (*ip6)) > 127 ((uintptr_t)mbuf_datastart(m0) + mbuf_maxlen(m0))) 128 return (0); /* out of bounds */ 129 130 flowlabel = ntohl(ip6->ip6_flow); 131 if ((flowlabel >> 28) != 6) 132 return ((u_int8_t)0); /* version mismatch! */ 133 ds_field = (flowlabel >> 20) & 0xff; 134 } 135#endif 136 return (ds_field); 137} 138 139void 140write_dsfield(struct mbuf *m, struct pf_mtag *t, u_int8_t dsfield) 141{ 142 struct mbuf *m0; 143 144 if (t->pftag_hdr == NULL || 145 !(t->pftag_flags & (PF_TAG_HDR_INET|PF_TAG_HDR_INET6))) 146 return; 147 148 /* verify that hdr is within the mbuf data */ 149 for (m0 = m; m0 != NULL; m0 = m0->m_next) 150 if (((caddr_t)t->pftag_hdr >= m0->m_data) && 151 ((caddr_t)t->pftag_hdr < m0->m_data + m0->m_len)) 152 break; 153 if (m0 == NULL) { 154 /* ick, tag info is stale */ 155 printf("%s: can't locate header!\n", __func__); 156 return; 157 } 158 159 if (t->pftag_flags & PF_TAG_HDR_INET) { 160 struct ip *ip = (struct ip *)(void *)t->pftag_hdr; 161 u_int8_t old; 162 int32_t sum; 163 164 if (((uintptr_t)ip + sizeof (*ip)) > 165 ((uintptr_t)mbuf_datastart(m0) + mbuf_maxlen(m0))) 166 return; /* out of bounds */ 167 168 if (ip->ip_v != 4) 169 return; /* version mismatch! */ 170 old = ip->ip_tos; 171 dsfield |= old & 3; /* leave CU bits */ 172 if (old == dsfield) 173 return; 174 ip->ip_tos = dsfield; 175 /* 176 * update checksum (from RFC1624) 177 * HC' = ~(~HC + ~m + m') 178 */ 179 sum = ~ntohs(ip->ip_sum) & 0xffff; 180 sum += 0xff00 + (~old & 0xff) + dsfield; 181 sum = (sum >> 16) + (sum & 0xffff); 182 sum += (sum >> 16); /* add carry */ 183 184 ip->ip_sum = htons(~sum & 0xffff); 185 } 186#if INET6 187 else if (t->pftag_flags & PF_TAG_HDR_INET6) { 188 struct ip6_hdr *ip6 = (struct ip6_hdr *)t->pftag_hdr; 189 u_int32_t flowlabel; 190 191 if (((uintptr_t)ip6 + sizeof (*ip6)) > 192 ((uintptr_t)mbuf_datastart(m0) + mbuf_maxlen(m0))) 193 return; /* out of bounds */ 194 195 flowlabel = ntohl(ip6->ip6_flow); 196 if ((flowlabel >> 28) != 6) 197 return; /* version mismatch! */ 198 flowlabel = (flowlabel & 0xf03fffff) | (dsfield << 20); 199 ip6->ip6_flow = htonl(flowlabel); 200 } 201#endif 202} 203 204/* 205 * try to mark CE bit to the packet. 206 * returns 1 if successfully marked, 0 otherwise. 207 */ 208int 209mark_ecn(struct mbuf *m, struct pf_mtag *t, int flags) 210{ 211 struct mbuf *m0; 212 void *hdr; 213 int af; 214 215 if ((hdr = t->pftag_hdr) == NULL || 216 !(t->pftag_flags & (PF_TAG_HDR_INET|PF_TAG_HDR_INET6))) 217 return (0); 218 219 /* verify that hdr is within the mbuf data */ 220 for (m0 = m; m0 != NULL; m0 = m0->m_next) 221 if (((caddr_t)hdr >= m0->m_data) && 222 ((caddr_t)hdr < m0->m_data + m0->m_len)) 223 break; 224 if (m0 == NULL) { 225 /* ick, tag info is stale */ 226 printf("%s: can't locate header!\n", __func__); 227 return (0); 228 } 229 230 if (t->pftag_flags & PF_TAG_HDR_INET) 231 af = AF_INET; 232 else if (t->pftag_flags & PF_TAG_HDR_INET6) 233 af = AF_INET6; 234 else 235 af = AF_UNSPEC; 236 237 switch (af) { 238 case AF_INET: 239 if (flags & CLASSQF_ECN4) { /* REDF_ECN4 == BLUEF_ECN4 */ 240 struct ip *ip = hdr; 241 u_int8_t otos; 242 int sum; 243 244 if (((uintptr_t)ip + sizeof (*ip)) > 245 ((uintptr_t)mbuf_datastart(m0) + mbuf_maxlen(m0))) 246 return (0); /* out of bounds */ 247 248 if (ip->ip_v != 4) 249 return (0); /* version mismatch! */ 250 if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT) 251 return (0); /* not-ECT */ 252 if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_CE) 253 return (1); /* already marked */ 254 255 /* 256 * ecn-capable but not marked, 257 * mark CE and update checksum 258 */ 259 otos = ip->ip_tos; 260 ip->ip_tos |= IPTOS_ECN_CE; 261 /* 262 * update checksum (from RFC1624) only if hw 263 * checksum is not supported. 264 * HC' = ~(~HC + ~m + m') 265 */ 266 if (!(m->m_pkthdr.csum_flags & CSUM_DELAY_IP)) { 267 sum = ~ntohs(ip->ip_sum) & 0xffff; 268 sum += (~otos & 0xffff) + ip->ip_tos; 269 sum = (sum >> 16) + (sum & 0xffff); 270 sum += (sum >> 16); /* add carry */ 271 ip->ip_sum = htons(~sum & 0xffff); 272 } 273 return (1); 274 } 275 break; 276#if INET6 277 case AF_INET6: 278 if (flags & CLASSQF_ECN6) { /* REDF_ECN6 == BLUEF_ECN6 */ 279 struct ip6_hdr *ip6 = hdr; 280 u_int32_t flowlabel; 281 282 if (((uintptr_t)ip6 + sizeof (*ip6)) > 283 ((uintptr_t)mbuf_datastart(m0) + mbuf_maxlen(m0))) 284 return (0); /* out of bounds */ 285 286 flowlabel = ntohl(ip6->ip6_flow); 287 if ((flowlabel >> 28) != 6) 288 return (0); /* version mismatch! */ 289 if ((flowlabel & (IPTOS_ECN_MASK << 20)) == 290 (IPTOS_ECN_NOTECT << 20)) 291 return (0); /* not-ECT */ 292 if ((flowlabel & (IPTOS_ECN_MASK << 20)) == 293 (IPTOS_ECN_CE << 20)) 294 return (1); /* already marked */ 295 /* 296 * ecn-capable but not marked, mark CE 297 */ 298 flowlabel |= (IPTOS_ECN_CE << 20); 299 ip6->ip6_flow = htonl(flowlabel); 300 return (1); 301 } 302 break; 303#endif /* INET6 */ 304 } 305 306 /* not marked */ 307 return (0); 308} 309#endif /* PF_ECN */ 310