1 //==========================================================================
3 // src/sys/netinet/in_cksum.c
5 //==========================================================================
6 //####BSDCOPYRIGHTBEGIN####
8 // -------------------------------------------
10 // Portions of this software may have been derived from OpenBSD,
11 // FreeBSD or other sources, and are covered by the appropriate
12 // copyright disclaimers included herein.
14 // Portions created by Red Hat are
15 // Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
17 // -------------------------------------------
19 //####BSDCOPYRIGHTEND####
20 //==========================================================================
22 /* $FreeBSD: src/sys/alpha/alpha/in_cksum.c,v 1.2.2.2 2001/05/04 15:36:43 ru Exp $ */
23 /* $NetBSD: in_cksum.c,v 1.7 1997/09/02 13:18:15 thorpej Exp $ */
26 * Copyright (c) 1988, 1992, 1993
27 * The Regents of the University of California. All rights reserved.
29 * Matt Thomas <matt@3am-software.com>
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93
62 #include <sys/param.h>
64 #include <netinet/in_systm.h>
65 #include <netinet/in.h>
66 #include <netinet/ip.h>
69 * Checksum routine for Internet Protocol family headers
70 * (Portable Alpha version).
72 * This routine is very heavily used in the network
73 * code and should be modified for each CPU to be as fast as possible.
76 #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
80 sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
85 l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
86 sum = l_util.s[0] + l_util.s[1]; \
90 static const u_int32_t in_masks[] = {
91 #if BYTE_ORDER == BIG_ENDIAN
92 /*0 bytes*/ /*1 byte*/ /*2 bytes*/ /*3 bytes*/
93 0x00000000, 0xFF000000, 0xFFFF0000, 0xFFFFFF00, /* offset 0 */
94 0x00000000, 0x00FF0000, 0x00FFFF00, 0x00FFFFFF, /* offset 1 */
95 0x00000000, 0x0000FF00, 0x0000FFFF, 0x0000FFFF, /* offset 2 */
96 0x00000000, 0x000000FF, 0x000000FF, 0x000000FF, /* offset 3 */
98 /*0 bytes*/ /*1 byte*/ /*2 bytes*/ /*3 bytes*/
99 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF, /* offset 0 */
100 0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00, /* offset 1 */
101 0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000, /* offset 2 */
102 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, /* offset 3 */
116 u_int64_t in_cksumdata __P((caddr_t buf, int len));
119 in_cksumdata(caddr_t buf, int len)
121 const u_int32_t *lw = (u_int32_t *) buf;
127 if ((3 & (long) lw) == 0 && len == 20) {
128 sum = (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4];
133 if ((offset = 3 & (long) lw) != 0) {
134 const u_int32_t *masks = in_masks + (offset << 2);
135 lw = (u_int32_t *) (((long) lw) - offset);
136 sum = *lw++ & masks[len >= 3 ? 3 : len];
145 * Force to cache line boundary.
147 offset = 32 - (0x1f & (long) lw);
148 if (offset < 32 && len > offset) {
151 sum += (u_int64_t) lw[0];
155 sum += (u_int64_t) lw[0] + lw[1];
159 sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
165 * access prefilling to start load of next cache line.
166 * then add current cache line
167 * save result of prefilling for loop iteration.
170 while ((len -= 32) >= 4) {
171 u_int64_t prefilling = lw[8];
172 sum += prefilled + lw[1] + lw[2] + lw[3]
173 + lw[4] + lw[5] + lw[6] + lw[7];
175 prefilled = prefilling;
178 sum += prefilled + lw[1] + lw[2] + lw[3]
179 + lw[4] + lw[5] + lw[6] + lw[7];
184 while ((len -= 16) >= 0) {
185 sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
189 while ((len -= 4) >= 0) {
190 sum += (u_int64_t) *lw++;
194 sum += (u_int64_t) (in_masks[len] & *lw);
200 in_addword(u_short a, u_short b)
202 u_int32_t sum = a + b;
209 in_pseudo(u_int32_t a, u_int32_t b, u_int32_t c)
215 sum = (u_int64_t) a + b + c;
221 in_cksum(struct mbuf *m, int len)
223 register u_int64_t sum = 0;
224 register int mlen = 0;
225 register int clen = 0;
226 register caddr_t addr;
230 for (; m && len; m = m->m_next) {
236 addr = mtod(m, caddr_t);
237 if ((clen ^ (long) addr) & 1)
238 sum += in_cksumdata(addr, mlen) << 8;
240 sum += in_cksumdata(addr, mlen);
246 return (~sum & 0xffff);
250 in_cksum_skip(struct mbuf *m, int len, int skip)
260 for (; skip && m; m = m->m_next) {
261 if (m->m_len > skip) {
262 mlen = m->m_len - skip;
263 addr = mtod(m, caddr_t) + skip;
270 for (; m && len; m = m->m_next) {
274 addr = mtod(m, caddr_t);
278 if ((clen ^ (long) addr) & 1)
279 sum += in_cksumdata(addr, mlen) << 8;
281 sum += in_cksumdata(addr, mlen);
287 return (~sum & 0xffff);
290 u_int in_cksum_hdr(const struct ip *ip)
292 u_int64_t sum = in_cksumdata((caddr_t) ip, sizeof(struct ip));
296 return (~sum & 0xffff);