]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/in6_cksum.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / netinet6 / in6_cksum.c
CommitLineData
b0d623f7
A
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 */
1c79356b
A
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
b0d623f7
A
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
1c79356b
A
122#include <sys/param.h>
123#include <sys/mbuf.h>
124#include <sys/systm.h>
2d21ac55 125#include <kern/debug.h>
1c79356b
A
126#include <netinet/in.h>
127#include <netinet/ip6.h>
128
129#include <net/net_osdep.h>
130
b0d623f7
A
131#include <machine/endian.h>
132
133
134#if defined(__arm__) && __ARM_ARCH__ >= 6
135extern int cpu_in_cksum(struct mbuf *m, int len, int off, uint32_t initial_sum);
136
137u_int16_t
138inet6_cksum(struct mbuf *m, unsigned int nxt, unsigned int off,
139 unsigned int len)
140{
141 union {
142 uint16_t words[16];
143 struct {
144 struct in6_addr ip6_src;
145 struct in6_addr ip6_dst;
146 } addrs;
147 } u;
148 const struct in6_addr *in6_src;
149 const struct in6_addr *in6_dst;
150 const struct ip6_hdr *ip6;
151 uint32_t sum;
152 const uint16_t *w;
153 const char *cp;
154
155 if (off < sizeof (struct ip6_hdr))
156 panic("inet6_cksum: offset too short for IPv6 header");
157 if (m->m_len < sizeof (struct ip6_hdr))
158 panic("inet6_cksum: mbuf too short for IPv6 header");
159
160 if (nxt == 0)
161 return (cpu_in_cksum(m, len, off, 0));
162
163 /*
164 * Compute the equivalent of:
165 * struct ip6_hdr_pseudo ip6;
166 *
167 * bzero(sizeof (*ip6));
168 * ip6.ip6ph_nxt = nxt;
169 * ip6.ip6ph_len = htonl(len);
170 * ipv6.ip6ph_src = mtod(m, struct ip6_hdr *)->ip6_src;
171 * in6_clearscope(&ip6->ip6ph_src);
172 * ipv6.ip6ph_dst = mtod(m, struct ip6_hdr *)->ip6_dst;
173 * in6_clearscope(&ip6->ip6ph_dst);
174 * sum = one_add(&ip6);
175 */
176
177#if BYTE_ORDER == LITTLE_ENDIAN
178 sum = ((len & 0xffff) + ((len >> 16) & 0xffff) + nxt) << 8;
179#else
180 sum = (len & 0xffff) + ((len >> 16) & 0xffff) + nxt;
181#endif
182 cp = mtod(m, const char *);
183 w = (const uint16_t *)(cp + offsetof(struct ip6_hdr, ip6_src));
184 ip6 = (const void *)cp;
185 if ((uintptr_t)w % 2 == 0) {
186 in6_src = &ip6->ip6_src;
187 in6_dst = &ip6->ip6_dst;
188 } else {
189 memcpy(&u, &ip6->ip6_src, 32);
190 w = u.words;
191 in6_src = &u.addrs.ip6_src;
192 in6_dst = &u.addrs.ip6_dst;
193 }
194
195 sum += w[0];
196 if (!IN6_IS_SCOPE_EMBED(in6_src))
197 sum += w[1];
198 sum += w[2];
199 sum += w[3];
200 sum += w[4];
201 sum += w[5];
202 sum += w[6];
203 sum += w[7];
204 w += 8;
205 sum += w[0];
206 if (!IN6_IS_SCOPE_EMBED(in6_dst))
207 sum += w[1];
208 sum += w[2];
209 sum += w[3];
210 sum += w[4];
211 sum += w[5];
212 sum += w[6];
213 sum += w[7];
214
215 return (cpu_in_cksum(m, len, off, sum));
216}
217
218#else
219
1c79356b
A
220/*
221 * Checksum routine for Internet Protocol family headers (Portable Version).
222 *
223 * This routine is very heavily used in the network
224 * code and should be modified for each CPU to be as fast as possible.
225 */
226
227#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
228#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
229
1c79356b
A
230/*
231 * m MUST contain a continuous IP6 header.
232 * off is a offset where TCP/UDP/ICMP6 header starts.
233 * len is a total length of a transport segment.
234 * (e.g. TCP header + TCP payload)
235 */
236
2d21ac55
A
237u_int16_t
238inet6_cksum(struct mbuf *m, unsigned int nxt, unsigned int off,
239 unsigned int len)
1c79356b 240{
9bccf70c
A
241 u_int16_t *w;
242 int sum = 0;
243 int mlen = 0;
1c79356b 244 int byte_swapped = 0;
2d21ac55 245 struct ip6_hdr *ip6;
9bccf70c
A
246 union {
247 u_int16_t phs[4];
248 struct {
249 u_int32_t ph_len;
250 u_int8_t ph_zero[3];
251 u_int8_t ph_nxt;
252 } ph __attribute__((__packed__));
253 } uph;
1c79356b
A
254 union {
255 u_int8_t c[2];
256 u_int16_t s;
257 } s_util;
258 union {
259 u_int16_t s[2];
260 u_int32_t l;
261 } l_util;
262
263 /* sanity check */
b0d623f7 264 if ((m->m_flags & M_PKTHDR) && m->m_pkthdr.len < off + len) {
2d21ac55
A
265 panic("inet6_cksum: mbuf len (%d) < off+len (%d+%d)\n",
266 m->m_pkthdr.len, off, len);
1c79356b
A
267 }
268
2d21ac55
A
269 if (nxt != 0) {
270 bzero(&uph, sizeof (uph));
9bccf70c 271
2d21ac55
A
272 /*
273 * First create IP6 pseudo header and calculate a summary.
274 */
275 ip6 = mtod(m, struct ip6_hdr *);
276 w = (u_int16_t *)&ip6->ip6_src;
277 uph.ph.ph_len = htonl(len);
278 uph.ph.ph_nxt = nxt;
1c79356b 279
2d21ac55
A
280 /* IPv6 source address */
281 sum += w[0];
282 if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
283 sum += w[1];
284 sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5];
285 sum += w[6]; sum += w[7];
286 /* IPv6 destination address */
287 sum += w[8];
288 if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
289 sum += w[9];
290 sum += w[10]; sum += w[11]; sum += w[12]; sum += w[13];
291 sum += w[14]; sum += w[15];
292 /* Payload length and upper layer identifier */
293 sum += uph.phs[0]; sum += uph.phs[1];
294 sum += uph.phs[2]; sum += uph.phs[3];
295 }
1c79356b 296
1c79356b
A
297 /*
298 * Secondly calculate a summary of the first mbuf excluding offset.
299 */
300 while (m != NULL && off > 0) {
301 if (m->m_len <= off)
302 off -= m->m_len;
303 else
304 break;
305 m = m->m_next;
306 }
307 w = (u_int16_t *)(mtod(m, u_char *) + off);
308 mlen = m->m_len - off;
309 if (len < mlen)
310 mlen = len;
311 len -= mlen;
312 /*
313 * Force to even boundary.
314 */
b0d623f7 315 if ((1 & (intptr_t) w) && (mlen > 0)) {
1c79356b
A
316 REDUCE;
317 sum <<= 8;
318 s_util.c[0] = *(u_char *)w;
319 w = (u_int16_t *)((char *)w + 1);
320 mlen--;
321 byte_swapped = 1;
322 }
323 /*
324 * Unroll the loop to make overhead from
325 * branches &c small.
326 */
327 while ((mlen -= 32) >= 0) {
328 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
329 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
330 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
331 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
332 w += 16;
333 }
334 mlen += 32;
335 while ((mlen -= 8) >= 0) {
336 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
337 w += 4;
338 }
339 mlen += 8;
340 if (mlen == 0 && byte_swapped == 0)
341 goto next;
342 REDUCE;
343 while ((mlen -= 2) >= 0) {
344 sum += *w++;
345 }
346 if (byte_swapped) {
347 REDUCE;
348 sum <<= 8;
349 byte_swapped = 0;
350 if (mlen == -1) {
351 s_util.c[1] = *(char *)w;
352 sum += s_util.s;
353 mlen = 0;
354 } else
355 mlen = -1;
356 } else if (mlen == -1)
357 s_util.c[0] = *(char *)w;
358 next:
359 m = m->m_next;
360
361 /*
362 * Lastly calculate a summary of the rest of mbufs.
363 */
2d21ac55 364
1c79356b
A
365 for (;m && len; m = m->m_next) {
366 if (m->m_len == 0)
367 continue;
368 w = mtod(m, u_int16_t *);
369 if (mlen == -1) {
370 /*
371 * The first byte of this mbuf is the continuation
372 * of a word spanning between this mbuf and the
373 * last mbuf.
374 *
375 * s_util.c[0] is already saved when scanning previous
376 * mbuf.
377 */
378 s_util.c[1] = *(char *)w;
379 sum += s_util.s;
380 w = (u_int16_t *)((char *)w + 1);
381 mlen = m->m_len - 1;
382 len--;
383 } else
384 mlen = m->m_len;
385 if (len < mlen)
386 mlen = len;
387 len -= mlen;
388 /*
389 * Force to even boundary.
390 */
b0d623f7 391 if ((1 & (intptr_t) w) && (mlen > 0)) {
1c79356b
A
392 REDUCE;
393 sum <<= 8;
394 s_util.c[0] = *(u_char *)w;
395 w = (u_int16_t *)((char *)w + 1);
396 mlen--;
397 byte_swapped = 1;
398 }
399 /*
400 * Unroll the loop to make overhead from
401 * branches &c small.
402 */
403 while ((mlen -= 32) >= 0) {
404 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
405 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
406 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
407 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
408 w += 16;
409 }
410 mlen += 32;
411 while ((mlen -= 8) >= 0) {
412 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
413 w += 4;
414 }
415 mlen += 8;
416 if (mlen == 0 && byte_swapped == 0)
417 continue;
418 REDUCE;
419 while ((mlen -= 2) >= 0) {
420 sum += *w++;
421 }
422 if (byte_swapped) {
423 REDUCE;
424 sum <<= 8;
425 byte_swapped = 0;
426 if (mlen == -1) {
427 s_util.c[1] = *(char *)w;
428 sum += s_util.s;
429 mlen = 0;
430 } else
431 mlen = -1;
432 } else if (mlen == -1)
433 s_util.c[0] = *(char *)w;
434 }
435 if (len)
2d21ac55 436 printf("inet6_cksum: out of data by %d\n", len);
1c79356b
A
437 if (mlen == -1) {
438 /* The last mbuf has odd # of bytes. Follow the
439 standard (the odd byte may be shifted left by 8 bits
440 or not as determined by endian-ness of the machine) */
441 s_util.c[1] = 0;
442 sum += s_util.s;
443 }
444 REDUCE;
445 return (~sum & 0xffff);
446}
b0d623f7
A
447
448#endif