in_cksum.c revision 209975
1757Sdg/* $FreeBSD: head/sys/powerpc/powerpc/in_cksum.c 209975 2010-07-13 05:32:19Z nwhitehorn $ */
2757Sdg/* $NetBSD: in_cksum.c,v 1.7 1997/09/02 13:18:15 thorpej Exp $ */
3757Sdg
4757Sdg/*-
5757Sdg * Copyright (c) 1988, 1992, 1993
6757Sdg *	The Regents of the University of California.  All rights reserved.
7757Sdg * Copyright (c) 1996
8757Sdg *	Matt Thomas <matt@3am-software.com>
9757Sdg *
10757Sdg * Redistribution and use in source and binary forms, with or without
11757Sdg * modification, are permitted provided that the following conditions
12757Sdg * are met:
13757Sdg * 1. Redistributions of source code must retain the above copyright
14757Sdg *    notice, this list of conditions and the following disclaimer.
15757Sdg * 2. Redistributions in binary form must reproduce the above copyright
16757Sdg *    notice, this list of conditions and the following disclaimer in the
17757Sdg *    documentation and/or other materials provided with the distribution.
18757Sdg * 3. All advertising materials mentioning features or use of this software
19757Sdg *    must display the following acknowledgement:
20757Sdg *	This product includes software developed by the University of
21757Sdg *	California, Berkeley and its contributors.
22757Sdg * 4. Neither the name of the University nor the names of its contributors
23757Sdg *    may be used to endorse or promote products derived from this software
24757Sdg *    without specific prior written permission.
25757Sdg *
26757Sdg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27757Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28757Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29757Sdg * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30757Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31757Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32757Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
334929Sbde * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34757Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35757Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36757Sdg * SUCH DAMAGE.
37757Sdg *
38757Sdg *	@(#)in_cksum.c	8.1 (Berkeley) 6/10/93
39757Sdg */
402056Swollman
41757Sdg#include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
422056Swollman
43757Sdg#include <sys/param.h>
442056Swollman#include <sys/mbuf.h>
451321Sdg#include <sys/systm.h>
462056Swollman#include <netinet/in_systm.h>
472056Swollman#include <netinet/in.h>
48757Sdg#include <netinet/ip.h>
492056Swollman#include <machine/in_cksum.h>
50757Sdg
51757Sdg/*
52757Sdg * Checksum routine for Internet Protocol family headers
53757Sdg *    (Portable Alpha version).
54757Sdg *
55757Sdg * This routine is very heavily used in the network
56757Sdg * code and should be modified for each CPU to be as fast as possible.
57757Sdg */
58757Sdg
59757Sdg#define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
60757Sdg#define REDUCE32							  \
61757Sdg    {									  \
621321Sdg	q_util.q = sum;							  \
631321Sdg	sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3];	  \
641321Sdg    }
651321Sdg#define REDUCE16							  \
661321Sdg    {									  \
67757Sdg	q_util.q = sum;							  \
68757Sdg	l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
69757Sdg	sum = l_util.s[0] + l_util.s[1];				  \
701321Sdg	ADDCARRY(sum);							  \
711321Sdg    }
721321Sdg
731321Sdgstatic const u_int32_t in_masks[] = {
741321Sdg#if 0
751321Sdg	/*0 bytes*/ /*1 byte*/	/*2 bytes*/ /*3 bytes*/
761321Sdg	0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF,	/* offset 0 */
771321Sdg	0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00,	/* offset 1 */
781321Sdg	0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000,	/* offset 2 */
791321Sdg	0x00000000, 0xFF000000, 0xFF000000, 0xFF000000,	/* offset 3 */
801321Sdg#else
811321Sdg	/*0 bytes*/ /*1 byte*/	/*2 bytes*/ /*3 bytes*/
821321Sdg	0x00000000, 0xFF000000, 0xFFFF0000, 0xFFFFFF00,	/* offset 0 */
831321Sdg	0x00000000, 0x00FF0000, 0x00FFFF00, 0x00FFFFFF,	/* offset 1 */
841321Sdg	0x00000000, 0x0000FF00, 0x0000FFFF, 0x0000FFFF,	/* offset 2 */
851321Sdg	0x00000000, 0x000000FF, 0x000000FF, 0x000000FF,	/* offset 3 */
86757Sdg#endif
871321Sdg};
881321Sdg
89757Sdgunion l_util {
901321Sdg	u_int16_t s[2];
91757Sdg	u_int32_t l;
92757Sdg};
931321Sdgunion q_util {
941321Sdg	u_int16_t s[4];
951321Sdg	u_int32_t l[2];
96757Sdg	u_int64_t q;
97757Sdg};
98757Sdg
99757Sdgstatic u_int64_t
100757Sdgin_cksumdata(const void *buf, int len)
101757Sdg{
102757Sdg	const u_int32_t *lw = (const u_int32_t *) buf;
103757Sdg	u_int64_t sum = 0;
104757Sdg	u_int64_t prefilled;
105757Sdg	int offset;
106757Sdg	union q_util q_util;
107757Sdg
108757Sdg	if ((3 & (long) lw) == 0 && len == 20) {
109757Sdg	     sum = (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4];
110757Sdg	     REDUCE32;
111757Sdg	     return sum;
112757Sdg	}
113757Sdg
114757Sdg	if ((offset = 3 & (long) lw) != 0) {
115757Sdg		const u_int32_t *masks = in_masks + (offset << 2);
116757Sdg		lw = (u_int32_t *) (((long) lw) - offset);
117757Sdg		sum = *lw++ & masks[len >= 3 ? 3 : len];
118757Sdg		len -= 4 - offset;
119757Sdg		if (len <= 0) {
120757Sdg			REDUCE32;
121757Sdg			return sum;
122757Sdg		}
123757Sdg	}
124757Sdg#if 0
125757Sdg	/*
126757Sdg	 * Force to cache line boundary.
127757Sdg	 */
128757Sdg	offset = 32 - (0x1f & (long) lw);
129757Sdg	if (offset < 32 && len > offset) {
130757Sdg		len -= offset;
131757Sdg		if (4 & offset) {
132757Sdg			sum += (u_int64_t) lw[0];
1334929Sbde			lw += 1;
1344929Sbde		}
1354929Sbde		if (8 & offset) {
1364929Sbde			sum += (u_int64_t) lw[0] + lw[1];
1374929Sbde			lw += 2;
138757Sdg		}
1391321Sdg		if (16 & offset) {
1401321Sdg			sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
141757Sdg			lw += 4;
142757Sdg		}
143757Sdg	}
144757Sdg#endif
145757Sdg	/*
146757Sdg	 * access prefilling to start load of next cache line.
1471321Sdg	 * then add current cache line
1481321Sdg	 * save result of prefilling for loop iteration.
1491321Sdg	 */
150757Sdg	prefilled = lw[0];
151757Sdg	while ((len -= 32) >= 4) {
1521321Sdg		u_int64_t prefilling = lw[8];
1531321Sdg		sum += prefilled + lw[1] + lw[2] + lw[3]
154757Sdg			+ lw[4] + lw[5] + lw[6] + lw[7];
1554929Sbde		lw += 8;
1561321Sdg		prefilled = prefilling;
1571321Sdg	}
158757Sdg	if (len >= 0) {
159757Sdg		sum += prefilled + lw[1] + lw[2] + lw[3]
160757Sdg			+ lw[4] + lw[5] + lw[6] + lw[7];
161757Sdg		lw += 8;
162757Sdg	} else {
163757Sdg		len += 32;
164757Sdg	}
165757Sdg	while ((len -= 16) >= 0) {
166757Sdg		sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
167757Sdg		lw += 4;
168757Sdg	}
169757Sdg	len += 16;
170757Sdg	while ((len -= 4) >= 0) {
171757Sdg		sum += (u_int64_t) *lw++;
172757Sdg	}
173757Sdg	len += 4;
174757Sdg	if (len > 0)
175757Sdg		sum += (u_int64_t) (in_masks[len] & *lw);
176757Sdg	REDUCE32;
177757Sdg	return sum;
178757Sdg}
179757Sdg
180757Sdgu_short
181757Sdgin_addword(u_short a, u_short b)
182757Sdg{
183757Sdg	u_int64_t sum = a + b;
184757Sdg
185757Sdg	ADDCARRY(sum);
186757Sdg	return (sum);
187757Sdg}
188757Sdg
189757Sdgu_short
190757Sdgin_pseudo(u_int32_t a, u_int32_t b, u_int32_t c)
191757Sdg{
192757Sdg	u_int64_t sum;
193757Sdg	union q_util q_util;
1941321Sdg	union l_util l_util;
195757Sdg
196757Sdg	sum = (u_int64_t) a + b + c;
197757Sdg	REDUCE16;
198757Sdg	return (sum);
199757Sdg}
200757Sdg
2011321Sdgu_short
202757Sdgin_cksum_skip(struct mbuf *m, int len, int skip)
2031321Sdg{
204757Sdg	u_int64_t sum = 0;
2051321Sdg	int mlen = 0;
206757Sdg	int clen = 0;
207757Sdg	caddr_t addr;
2081321Sdg	union q_util q_util;
2091321Sdg	union l_util l_util;
2101321Sdg
2111321Sdg        len -= skip;
2121321Sdg        for (; skip && m; m = m->m_next) {
2131321Sdg                if (m->m_len > skip) {
2141321Sdg                        mlen = m->m_len - skip;
2151321Sdg			addr = mtod(m, caddr_t) + skip;
2161321Sdg                        goto skip_start;
2171321Sdg                } else {
2181321Sdg                        skip -= m->m_len;
219757Sdg                }
220757Sdg        }
2211321Sdg
2221321Sdg	for (; m && len; m = m->m_next) {
2234929Sbde		if (m->m_len == 0)
2241321Sdg			continue;
2251321Sdg		mlen = m->m_len;
226757Sdg		addr = mtod(m, caddr_t);
227757Sdgskip_start:
228757Sdg		if (len < mlen)
229757Sdg			mlen = len;
230757Sdg
231757Sdg		if ((clen ^ (long) addr) & 1)
232757Sdg		    sum += in_cksumdata(addr, mlen) << 8;
2331321Sdg		else
234757Sdg		    sum += in_cksumdata(addr, mlen);
235924Sdg
236757Sdg		clen += mlen;
237757Sdg		len -= mlen;
238757Sdg	}
239757Sdg	REDUCE16;
2401321Sdg	return (~sum & 0xffff);
241757Sdg}
242757Sdg
243757Sdgu_int in_cksum_hdr(const struct ip *ip)
2441321Sdg{
245757Sdg    u_int64_t sum = in_cksumdata(ip, sizeof(struct ip));
246757Sdg    union q_util q_util;
247757Sdg    union l_util l_util;
248757Sdg    REDUCE16;
249757Sdg    return (~sum & 0xffff);
250757Sdg}
251757Sdg