]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/classq/classq_util.c
xnu-6153.141.1.tar.gz
[apple/xnu.git] / bsd / net / classq / classq_util.c
CommitLineData
316670eb
A
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
39236c6e 85#if PF_ECN
316670eb
A
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 ||
0a7de745
A
96 !(t->pftag_flags & (PF_TAG_HDR_INET | PF_TAG_HDR_INET6))) {
97 return (u_int8_t)0;
98 }
316670eb
A
99
100 /* verify that hdr is within the mbuf data */
0a7de745 101 for (m0 = m; m0 != NULL; m0 = m0->m_next) {
316670eb 102 if (((caddr_t)t->pftag_hdr >= m0->m_data) &&
0a7de745 103 ((caddr_t)t->pftag_hdr < m0->m_data + m0->m_len)) {
316670eb 104 break;
0a7de745
A
105 }
106 }
316670eb
A
107 if (m0 == NULL) {
108 /* ick, tag info is stale */
109 printf("%s: can't locate header!\n", __func__);
0a7de745 110 return (u_int8_t)0;
316670eb
A
111 }
112
113 if (t->pftag_flags & PF_TAG_HDR_INET) {
114 struct ip *ip = (struct ip *)(void *)t->pftag_hdr;
115
0a7de745
A
116 if (((uintptr_t)ip + sizeof(*ip)) >
117 ((uintptr_t)mbuf_datastart(m0) + mbuf_maxlen(m0))) {
118 return 0; /* out of bounds */
119 }
120 if (ip->ip_v != 4) {
121 return (u_int8_t)0; /* version mismatch! */
122 }
316670eb
A
123 ds_field = ip->ip_tos;
124 }
125#if INET6
126 else if (t->pftag_flags & PF_TAG_HDR_INET6) {
127 struct ip6_hdr *ip6 = (struct ip6_hdr *)(void *)t->pftag_hdr;
128 u_int32_t flowlabel;
129
0a7de745
A
130 if (((uintptr_t)ip6 + sizeof(*ip6)) >
131 ((uintptr_t)mbuf_datastart(m0) + mbuf_maxlen(m0))) {
132 return 0; /* out of bounds */
133 }
316670eb 134 flowlabel = ntohl(ip6->ip6_flow);
0a7de745
A
135 if ((flowlabel >> 28) != 6) {
136 return (u_int8_t)0; /* version mismatch! */
137 }
316670eb
A
138 ds_field = (flowlabel >> 20) & 0xff;
139 }
140#endif
0a7de745 141 return ds_field;
316670eb
A
142}
143
144void
145write_dsfield(struct mbuf *m, struct pf_mtag *t, u_int8_t dsfield)
146{
147 struct mbuf *m0;
148
149 if (t->pftag_hdr == NULL ||
0a7de745 150 !(t->pftag_flags & (PF_TAG_HDR_INET | PF_TAG_HDR_INET6))) {
316670eb 151 return;
0a7de745 152 }
316670eb
A
153
154 /* verify that hdr is within the mbuf data */
0a7de745 155 for (m0 = m; m0 != NULL; m0 = m0->m_next) {
316670eb 156 if (((caddr_t)t->pftag_hdr >= m0->m_data) &&
0a7de745 157 ((caddr_t)t->pftag_hdr < m0->m_data + m0->m_len)) {
316670eb 158 break;
0a7de745
A
159 }
160 }
316670eb
A
161 if (m0 == NULL) {
162 /* ick, tag info is stale */
163 printf("%s: can't locate header!\n", __func__);
164 return;
165 }
166
167 if (t->pftag_flags & PF_TAG_HDR_INET) {
168 struct ip *ip = (struct ip *)(void *)t->pftag_hdr;
169 u_int8_t old;
170 int32_t sum;
171
0a7de745
A
172 if (((uintptr_t)ip + sizeof(*ip)) >
173 ((uintptr_t)mbuf_datastart(m0) + mbuf_maxlen(m0))) {
174 return; /* out of bounds */
175 }
176 if (ip->ip_v != 4) {
177 return; /* version mismatch! */
178 }
316670eb 179 old = ip->ip_tos;
0a7de745
A
180 dsfield |= old & 3; /* leave CU bits */
181 if (old == dsfield) {
316670eb 182 return;
0a7de745 183 }
316670eb
A
184 ip->ip_tos = dsfield;
185 /*
186 * update checksum (from RFC1624)
187 * HC' = ~(~HC + ~m + m')
188 */
189 sum = ~ntohs(ip->ip_sum) & 0xffff;
190 sum += 0xff00 + (~old & 0xff) + dsfield;
191 sum = (sum >> 16) + (sum & 0xffff);
192 sum += (sum >> 16); /* add carry */
193
194 ip->ip_sum = htons(~sum & 0xffff);
195 }
196#if INET6
197 else if (t->pftag_flags & PF_TAG_HDR_INET6) {
198 struct ip6_hdr *ip6 = (struct ip6_hdr *)t->pftag_hdr;
199 u_int32_t flowlabel;
200
0a7de745
A
201 if (((uintptr_t)ip6 + sizeof(*ip6)) >
202 ((uintptr_t)mbuf_datastart(m0) + mbuf_maxlen(m0))) {
203 return; /* out of bounds */
204 }
316670eb 205 flowlabel = ntohl(ip6->ip6_flow);
0a7de745
A
206 if ((flowlabel >> 28) != 6) {
207 return; /* version mismatch! */
208 }
316670eb
A
209 flowlabel = (flowlabel & 0xf03fffff) | (dsfield << 20);
210 ip6->ip6_flow = htonl(flowlabel);
211 }
212#endif
213}
214
215/*
216 * try to mark CE bit to the packet.
217 * returns 1 if successfully marked, 0 otherwise.
218 */
219int
220mark_ecn(struct mbuf *m, struct pf_mtag *t, int flags)
221{
0a7de745
A
222 struct mbuf *m0;
223 void *hdr;
224 int af;
316670eb
A
225
226 if ((hdr = t->pftag_hdr) == NULL ||
0a7de745
A
227 !(t->pftag_flags & (PF_TAG_HDR_INET | PF_TAG_HDR_INET6))) {
228 return 0;
229 }
316670eb
A
230
231 /* verify that hdr is within the mbuf data */
0a7de745 232 for (m0 = m; m0 != NULL; m0 = m0->m_next) {
316670eb 233 if (((caddr_t)hdr >= m0->m_data) &&
0a7de745 234 ((caddr_t)hdr < m0->m_data + m0->m_len)) {
316670eb 235 break;
0a7de745
A
236 }
237 }
316670eb
A
238 if (m0 == NULL) {
239 /* ick, tag info is stale */
240 printf("%s: can't locate header!\n", __func__);
0a7de745 241 return 0;
316670eb
A
242 }
243
0a7de745 244 if (t->pftag_flags & PF_TAG_HDR_INET) {
316670eb 245 af = AF_INET;
0a7de745 246 } else if (t->pftag_flags & PF_TAG_HDR_INET6) {
316670eb 247 af = AF_INET6;
0a7de745 248 } else {
316670eb 249 af = AF_UNSPEC;
0a7de745 250 }
316670eb
A
251
252 switch (af) {
253 case AF_INET:
0a7de745 254 if (flags & CLASSQF_ECN4) { /* REDF_ECN4 == BLUEF_ECN4 */
316670eb
A
255 struct ip *ip = hdr;
256 u_int8_t otos;
257 int sum;
258
0a7de745
A
259 if (((uintptr_t)ip + sizeof(*ip)) >
260 ((uintptr_t)mbuf_datastart(m0) + mbuf_maxlen(m0))) {
261 return 0; /* out of bounds */
262 }
263 if (ip->ip_v != 4) {
264 return 0; /* version mismatch! */
265 }
266 if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT) {
267 return 0; /* not-ECT */
268 }
269 if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_CE) {
270 return 1; /* already marked */
271 }
316670eb
A
272 /*
273 * ecn-capable but not marked,
274 * mark CE and update checksum
275 */
276 otos = ip->ip_tos;
277 ip->ip_tos |= IPTOS_ECN_CE;
278 /*
fe8ab488
A
279 * update checksum (from RFC1624) only if hw
280 * checksum is not supported.
316670eb
A
281 * HC' = ~(~HC + ~m + m')
282 */
fe8ab488
A
283 if (!(m->m_pkthdr.csum_flags & CSUM_DELAY_IP)) {
284 sum = ~ntohs(ip->ip_sum) & 0xffff;
285 sum += (~otos & 0xffff) + ip->ip_tos;
286 sum = (sum >> 16) + (sum & 0xffff);
287 sum += (sum >> 16); /* add carry */
288 ip->ip_sum = htons(~sum & 0xffff);
289 }
0a7de745 290 return 1;
316670eb
A
291 }
292 break;
293#if INET6
294 case AF_INET6:
0a7de745 295 if (flags & CLASSQF_ECN6) { /* REDF_ECN6 == BLUEF_ECN6 */
316670eb
A
296 struct ip6_hdr *ip6 = hdr;
297 u_int32_t flowlabel;
298
0a7de745
A
299 if (((uintptr_t)ip6 + sizeof(*ip6)) >
300 ((uintptr_t)mbuf_datastart(m0) + mbuf_maxlen(m0))) {
301 return 0; /* out of bounds */
302 }
316670eb 303 flowlabel = ntohl(ip6->ip6_flow);
0a7de745
A
304 if ((flowlabel >> 28) != 6) {
305 return 0; /* version mismatch! */
306 }
316670eb 307 if ((flowlabel & (IPTOS_ECN_MASK << 20)) ==
0a7de745
A
308 (IPTOS_ECN_NOTECT << 20)) {
309 return 0; /* not-ECT */
310 }
316670eb 311 if ((flowlabel & (IPTOS_ECN_MASK << 20)) ==
0a7de745
A
312 (IPTOS_ECN_CE << 20)) {
313 return 1; /* already marked */
314 }
316670eb
A
315 /*
316 * ecn-capable but not marked, mark CE
317 */
318 flowlabel |= (IPTOS_ECN_CE << 20);
319 ip6->ip6_flow = htonl(flowlabel);
0a7de745 320 return 1;
316670eb
A
321 }
322 break;
323#endif /* INET6 */
324 }
325
326 /* not marked */
0a7de745 327 return 0;
316670eb 328}
39236c6e 329#endif /* PF_ECN */