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