]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/in6_cksum.c
77dd7e1afb2e7e5ab55b767d42f656bb09213ab1
[apple/xnu.git] / bsd / netinet6 / in6_cksum.c
1 /*
2 * Copyright (c) 2009 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) 1995, 1996, 1997, and 1998 WIDE Project.
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. Neither the name of the project nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58 /*
59 * Copyright (c) 1988, 1992, 1993
60 * The Regents of the University of California. All rights reserved.
61 *
62 * Redistribution and use in source and binary forms, with or without
63 * modification, are permitted provided that the following conditions
64 * are met:
65 * 1. Redistributions of source code must retain the above copyright
66 * notice, this list of conditions and the following disclaimer.
67 * 2. Redistributions in binary form must reproduce the above copyright
68 * notice, this list of conditions and the following disclaimer in the
69 * documentation and/or other materials provided with the distribution.
70 * 3. All advertising materials mentioning features or use of this software
71 * must display the following acknowledgement:
72 * This product includes software developed by the University of
73 * California, Berkeley and its contributors.
74 * 4. Neither the name of the University nor the names of its contributors
75 * may be used to endorse or promote products derived from this software
76 * without specific prior written permission.
77 *
78 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
79 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
80 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
81 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
82 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
83 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
84 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
85 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
86 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
87 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
88 * SUCH DAMAGE.
89 *
90 * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93
91 */
92
93 /*-
94 * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
95 * All rights reserved.
96 *
97 * Redistribution and use in source and binary forms, with or without
98 * modification, are permitted provided that the following conditions
99 * are met:
100 *
101 * 1. Redistributions of source code must retain the above copyright
102 * notice, this list of conditions and the following disclaimer.
103 * 2. Redistributions in binary form must reproduce the above copyright
104 * notice, this list of conditions and the following disclaimer in
105 * the documentation and/or other materials provided with the
106 * distribution.
107 *
108 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
109 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
110 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
111 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
112 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
113 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
114 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
115 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
116 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
117 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
118 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
119 * SUCH DAMAGE.
120 */
121
122 #include <sys/param.h>
123 #include <sys/mbuf.h>
124 #include <sys/systm.h>
125 #include <kern/debug.h>
126 #include <netinet/in.h>
127 #include <netinet/ip6.h>
128
129 #include <net/net_osdep.h>
130
131 #include <machine/endian.h>
132
133
134
135 /*
136 * Checksum routine for Internet Protocol family headers (Portable Version).
137 *
138 * This routine is very heavily used in the network
139 * code and should be modified for each CPU to be as fast as possible.
140 */
141
142 #define ADDCARRY(x) do { if (x > 65535) { x -= 65535; } } while (0)
143 #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
144
145 /*
146 * m MUST contain a continuous IP6 header.
147 * off is a offset where TCP/UDP/ICMP6 header starts.
148 * len is a total length of a transport segment.
149 * (e.g. TCP header + TCP payload)
150 */
151
152 u_int16_t
153 inet6_cksum(struct mbuf *m, unsigned int nxt, unsigned int off,
154 unsigned int len)
155 {
156 u_int16_t *w;
157 int sum = 0;
158 int mlen = 0;
159 int byte_swapped = 0;
160 struct ip6_hdr *ip6;
161 union {
162 u_int16_t phs[4];
163 struct {
164 u_int32_t ph_len;
165 u_int8_t ph_zero[3];
166 u_int8_t ph_nxt;
167 } ph __attribute__((__packed__));
168 } uph;
169 union {
170 u_int8_t c[2];
171 u_int16_t s;
172 } s_util;
173 union {
174 u_int16_t s[2];
175 u_int32_t l;
176 } l_util;
177
178 /* sanity check */
179 if ((m->m_flags & M_PKTHDR) && m->m_pkthdr.len < off + len) {
180 panic("inet6_cksum: mbuf len (%d) < off+len (%d+%d)\n",
181 m->m_pkthdr.len, off, len);
182 }
183
184 if (nxt != 0) {
185 bzero(&uph, sizeof (uph));
186
187 /*
188 * First create IP6 pseudo header and calculate a summary.
189 */
190 ip6 = mtod(m, struct ip6_hdr *);
191 w = (u_int16_t *)&ip6->ip6_src;
192 uph.ph.ph_len = htonl(len);
193 uph.ph.ph_nxt = nxt;
194
195 /* IPv6 source address */
196 sum += w[0];
197 if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
198 sum += w[1];
199 sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5];
200 sum += w[6]; sum += w[7];
201 /* IPv6 destination address */
202 sum += w[8];
203 if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
204 sum += w[9];
205 sum += w[10]; sum += w[11]; sum += w[12]; sum += w[13];
206 sum += w[14]; sum += w[15];
207 /* Payload length and upper layer identifier */
208 sum += uph.phs[0]; sum += uph.phs[1];
209 sum += uph.phs[2]; sum += uph.phs[3];
210 }
211
212 /*
213 * Secondly calculate a summary of the first mbuf excluding offset.
214 */
215 while (m != NULL && off > 0) {
216 if (m->m_len <= off)
217 off -= m->m_len;
218 else
219 break;
220 m = m->m_next;
221 }
222 w = (u_int16_t *)(mtod(m, u_char *) + off);
223 mlen = m->m_len - off;
224 if (len < mlen)
225 mlen = len;
226 len -= mlen;
227 /*
228 * Force to even boundary.
229 */
230 if ((1 & (intptr_t) w) && (mlen > 0)) {
231 REDUCE;
232 sum <<= 8;
233 s_util.c[0] = *(u_char *)w;
234 w = (u_int16_t *)((char *)w + 1);
235 mlen--;
236 byte_swapped = 1;
237 }
238 /*
239 * Unroll the loop to make overhead from
240 * branches &c small.
241 */
242 while ((mlen -= 32) >= 0) {
243 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
244 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
245 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
246 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
247 w += 16;
248 }
249 mlen += 32;
250 while ((mlen -= 8) >= 0) {
251 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
252 w += 4;
253 }
254 mlen += 8;
255 if (mlen == 0 && byte_swapped == 0)
256 goto next;
257 REDUCE;
258 while ((mlen -= 2) >= 0) {
259 sum += *w++;
260 }
261 if (byte_swapped) {
262 REDUCE;
263 sum <<= 8;
264 byte_swapped = 0;
265 if (mlen == -1) {
266 s_util.c[1] = *(char *)w;
267 sum += s_util.s;
268 mlen = 0;
269 } else
270 mlen = -1;
271 } else if (mlen == -1)
272 s_util.c[0] = *(char *)w;
273 next:
274 m = m->m_next;
275
276 /*
277 * Lastly calculate a summary of the rest of mbufs.
278 */
279
280 for (;m && len; m = m->m_next) {
281 if (m->m_len == 0)
282 continue;
283 w = mtod(m, u_int16_t *);
284 if (mlen == -1) {
285 /*
286 * The first byte of this mbuf is the continuation
287 * of a word spanning between this mbuf and the
288 * last mbuf.
289 *
290 * s_util.c[0] is already saved when scanning previous
291 * mbuf.
292 */
293 s_util.c[1] = *(char *)w;
294 sum += s_util.s;
295 w = (u_int16_t *)((char *)w + 1);
296 mlen = m->m_len - 1;
297 len--;
298 } else
299 mlen = m->m_len;
300 if (len < mlen)
301 mlen = len;
302 len -= mlen;
303 /*
304 * Force to even boundary.
305 */
306 if ((1 & (intptr_t) w) && (mlen > 0)) {
307 REDUCE;
308 sum <<= 8;
309 s_util.c[0] = *(u_char *)w;
310 w = (u_int16_t *)((char *)w + 1);
311 mlen--;
312 byte_swapped = 1;
313 }
314 /*
315 * Unroll the loop to make overhead from
316 * branches &c small.
317 */
318 while ((mlen -= 32) >= 0) {
319 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
320 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
321 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
322 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
323 w += 16;
324 }
325 mlen += 32;
326 while ((mlen -= 8) >= 0) {
327 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
328 w += 4;
329 }
330 mlen += 8;
331 if (mlen == 0 && byte_swapped == 0)
332 continue;
333 REDUCE;
334 while ((mlen -= 2) >= 0) {
335 sum += *w++;
336 }
337 if (byte_swapped) {
338 REDUCE;
339 sum <<= 8;
340 byte_swapped = 0;
341 if (mlen == -1) {
342 s_util.c[1] = *(char *)w;
343 sum += s_util.s;
344 mlen = 0;
345 } else
346 mlen = -1;
347 } else if (mlen == -1)
348 s_util.c[0] = *(char *)w;
349 }
350 if (len)
351 printf("inet6_cksum: out of data by %d\n", len);
352 if (mlen == -1) {
353 /* The last mbuf has odd # of bytes. Follow the
354 standard (the odd byte may be shifted left by 8 bits
355 or not as determined by endian-ness of the machine) */
356 s_util.c[1] = 0;
357 sum += s_util.s;
358 }
359 REDUCE;
360 return (~sum & 0xffff);
361 }
362