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