1*ecbbe831SMark Johnston /*- 2*ecbbe831SMark Johnston * SPDX-License-Identifier: BSD-4-Clause 3*ecbbe831SMark Johnston * 4*ecbbe831SMark Johnston * Copyright (c) 1988, 1992, 1993 5*ecbbe831SMark Johnston * The Regents of the University of California. All rights reserved. 6*ecbbe831SMark Johnston * Copyright (c) 1996 7*ecbbe831SMark Johnston * Matt Thomas <matt@3am-software.com> 8*ecbbe831SMark Johnston * 9*ecbbe831SMark Johnston * Redistribution and use in source and binary forms, with or without 10*ecbbe831SMark Johnston * modification, are permitted provided that the following conditions 11*ecbbe831SMark Johnston * are met: 12*ecbbe831SMark Johnston * 1. Redistributions of source code must retain the above copyright 13*ecbbe831SMark Johnston * notice, this list of conditions and the following disclaimer. 14*ecbbe831SMark Johnston * 2. Redistributions in binary form must reproduce the above copyright 15*ecbbe831SMark Johnston * notice, this list of conditions and the following disclaimer in the 16*ecbbe831SMark Johnston * documentation and/or other materials provided with the distribution. 17*ecbbe831SMark Johnston * 3. All advertising materials mentioning features or use of this software 18*ecbbe831SMark Johnston * must display the following acknowledgement: 19*ecbbe831SMark Johnston * This product includes software developed by the University of 20*ecbbe831SMark Johnston * California, Berkeley and its contributors. 21*ecbbe831SMark Johnston * 4. Neither the name of the University nor the names of its contributors 22*ecbbe831SMark Johnston * may be used to endorse or promote products derived from this software 23*ecbbe831SMark Johnston * without specific prior written permission. 24*ecbbe831SMark Johnston * 25*ecbbe831SMark Johnston * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26*ecbbe831SMark Johnston * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27*ecbbe831SMark Johnston * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28*ecbbe831SMark Johnston * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29*ecbbe831SMark Johnston * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30*ecbbe831SMark Johnston * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31*ecbbe831SMark Johnston * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32*ecbbe831SMark Johnston * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33*ecbbe831SMark Johnston * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34*ecbbe831SMark Johnston * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35*ecbbe831SMark Johnston * SUCH DAMAGE. 36*ecbbe831SMark Johnston * 37*ecbbe831SMark Johnston * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 38*ecbbe831SMark Johnston */ 39*ecbbe831SMark Johnston 40*ecbbe831SMark Johnston #include <sys/cdefs.h> 41*ecbbe831SMark Johnston __FBSDID("$FreeBSD$"); 42*ecbbe831SMark Johnston 43*ecbbe831SMark Johnston #include <sys/param.h> 44*ecbbe831SMark Johnston #include <sys/mbuf.h> 45*ecbbe831SMark Johnston #include <sys/systm.h> 46*ecbbe831SMark Johnston #include <netinet/in_systm.h> 47*ecbbe831SMark Johnston #include <netinet/in.h> 48*ecbbe831SMark Johnston #include <netinet/ip.h> 49*ecbbe831SMark Johnston #include <machine/in_cksum.h> 50*ecbbe831SMark Johnston 51*ecbbe831SMark Johnston /* 52*ecbbe831SMark Johnston * These implementations may be overridden on a per-platform basis. 53*ecbbe831SMark Johnston */ 54*ecbbe831SMark Johnston #ifndef HAVE_MD_IN_CKSUM 55*ecbbe831SMark Johnston 56*ecbbe831SMark Johnston /* 57*ecbbe831SMark Johnston * Checksum routine for Internet Protocol family headers 58*ecbbe831SMark Johnston * (Portable Alpha version). 59*ecbbe831SMark Johnston * 60*ecbbe831SMark Johnston * This routine is very heavily used in the network 61*ecbbe831SMark Johnston * code and should be modified for each CPU to be as fast as possible. 62*ecbbe831SMark Johnston */ 63*ecbbe831SMark Johnston 64*ecbbe831SMark Johnston #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) 65*ecbbe831SMark Johnston #define REDUCE32 \ 66*ecbbe831SMark Johnston { \ 67*ecbbe831SMark Johnston q_util.q = sum; \ 68*ecbbe831SMark Johnston sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \ 69*ecbbe831SMark Johnston } 70*ecbbe831SMark Johnston #define REDUCE16 \ 71*ecbbe831SMark Johnston { \ 72*ecbbe831SMark Johnston q_util.q = sum; \ 73*ecbbe831SMark Johnston l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \ 74*ecbbe831SMark Johnston sum = l_util.s[0] + l_util.s[1]; \ 75*ecbbe831SMark Johnston ADDCARRY(sum); \ 76*ecbbe831SMark Johnston } 77*ecbbe831SMark Johnston 78*ecbbe831SMark Johnston static const u_int32_t in_masks[] = { 79*ecbbe831SMark Johnston #if _BYTE_ORDER == _LITTLE_ENDIAN 80*ecbbe831SMark Johnston /*0 bytes*/ /*1 byte*/ /*2 bytes*/ /*3 bytes*/ 81*ecbbe831SMark Johnston 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF, /* offset 0 */ 82*ecbbe831SMark Johnston 0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00, /* offset 1 */ 83*ecbbe831SMark Johnston 0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000, /* offset 2 */ 84*ecbbe831SMark Johnston 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, /* offset 3 */ 85*ecbbe831SMark Johnston #else 86*ecbbe831SMark Johnston /*0 bytes*/ /*1 byte*/ /*2 bytes*/ /*3 bytes*/ 87*ecbbe831SMark Johnston 0x00000000, 0xFF000000, 0xFFFF0000, 0xFFFFFF00, /* offset 0 */ 88*ecbbe831SMark Johnston 0x00000000, 0x00FF0000, 0x00FFFF00, 0x00FFFFFF, /* offset 1 */ 89*ecbbe831SMark Johnston 0x00000000, 0x0000FF00, 0x0000FFFF, 0x0000FFFF, /* offset 2 */ 90*ecbbe831SMark Johnston 0x00000000, 0x000000FF, 0x000000FF, 0x000000FF, /* offset 3 */ 91*ecbbe831SMark Johnston #endif 92*ecbbe831SMark Johnston }; 93*ecbbe831SMark Johnston 94*ecbbe831SMark Johnston union l_util { 95*ecbbe831SMark Johnston u_int16_t s[2]; 96*ecbbe831SMark Johnston u_int32_t l; 97*ecbbe831SMark Johnston }; 98*ecbbe831SMark Johnston union q_util { 99*ecbbe831SMark Johnston u_int16_t s[4]; 100*ecbbe831SMark Johnston u_int32_t l[2]; 101*ecbbe831SMark Johnston u_int64_t q; 102*ecbbe831SMark Johnston }; 103*ecbbe831SMark Johnston 104*ecbbe831SMark Johnston static u_int64_t 105*ecbbe831SMark Johnston in_cksumdata(const void *buf, int len) 106*ecbbe831SMark Johnston { 107*ecbbe831SMark Johnston const u_int32_t *lw = (const u_int32_t *) buf; 108*ecbbe831SMark Johnston u_int64_t sum = 0; 109*ecbbe831SMark Johnston u_int64_t prefilled; 110*ecbbe831SMark Johnston int offset; 111*ecbbe831SMark Johnston union q_util q_util; 112*ecbbe831SMark Johnston 113*ecbbe831SMark Johnston if ((3 & (long) lw) == 0 && len == 20) { 114*ecbbe831SMark Johnston sum = (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4]; 115*ecbbe831SMark Johnston REDUCE32; 116*ecbbe831SMark Johnston return sum; 117*ecbbe831SMark Johnston } 118*ecbbe831SMark Johnston 119*ecbbe831SMark Johnston if ((offset = 3 & (long) lw) != 0) { 120*ecbbe831SMark Johnston const u_int32_t *masks = in_masks + (offset << 2); 121*ecbbe831SMark Johnston lw = (u_int32_t *) (((long) lw) - offset); 122*ecbbe831SMark Johnston sum = *lw++ & masks[len >= 3 ? 3 : len]; 123*ecbbe831SMark Johnston len -= 4 - offset; 124*ecbbe831SMark Johnston if (len <= 0) { 125*ecbbe831SMark Johnston REDUCE32; 126*ecbbe831SMark Johnston return sum; 127*ecbbe831SMark Johnston } 128*ecbbe831SMark Johnston } 129*ecbbe831SMark Johnston #if 0 130*ecbbe831SMark Johnston /* 131*ecbbe831SMark Johnston * Force to cache line boundary. 132*ecbbe831SMark Johnston */ 133*ecbbe831SMark Johnston offset = 32 - (0x1f & (long) lw); 134*ecbbe831SMark Johnston if (offset < 32 && len > offset) { 135*ecbbe831SMark Johnston len -= offset; 136*ecbbe831SMark Johnston if (4 & offset) { 137*ecbbe831SMark Johnston sum += (u_int64_t) lw[0]; 138*ecbbe831SMark Johnston lw += 1; 139*ecbbe831SMark Johnston } 140*ecbbe831SMark Johnston if (8 & offset) { 141*ecbbe831SMark Johnston sum += (u_int64_t) lw[0] + lw[1]; 142*ecbbe831SMark Johnston lw += 2; 143*ecbbe831SMark Johnston } 144*ecbbe831SMark Johnston if (16 & offset) { 145*ecbbe831SMark Johnston sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3]; 146*ecbbe831SMark Johnston lw += 4; 147*ecbbe831SMark Johnston } 148*ecbbe831SMark Johnston } 149*ecbbe831SMark Johnston #endif 150*ecbbe831SMark Johnston /* 151*ecbbe831SMark Johnston * access prefilling to start load of next cache line. 152*ecbbe831SMark Johnston * then add current cache line 153*ecbbe831SMark Johnston * save result of prefilling for loop iteration. 154*ecbbe831SMark Johnston */ 155*ecbbe831SMark Johnston prefilled = lw[0]; 156*ecbbe831SMark Johnston while ((len -= 32) >= 4) { 157*ecbbe831SMark Johnston u_int64_t prefilling = lw[8]; 158*ecbbe831SMark Johnston sum += prefilled + lw[1] + lw[2] + lw[3] 159*ecbbe831SMark Johnston + lw[4] + lw[5] + lw[6] + lw[7]; 160*ecbbe831SMark Johnston lw += 8; 161*ecbbe831SMark Johnston prefilled = prefilling; 162*ecbbe831SMark Johnston } 163*ecbbe831SMark Johnston if (len >= 0) { 164*ecbbe831SMark Johnston sum += prefilled + lw[1] + lw[2] + lw[3] 165*ecbbe831SMark Johnston + lw[4] + lw[5] + lw[6] + lw[7]; 166*ecbbe831SMark Johnston lw += 8; 167*ecbbe831SMark Johnston } else { 168*ecbbe831SMark Johnston len += 32; 169*ecbbe831SMark Johnston } 170*ecbbe831SMark Johnston while ((len -= 16) >= 0) { 171*ecbbe831SMark Johnston sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3]; 172*ecbbe831SMark Johnston lw += 4; 173*ecbbe831SMark Johnston } 174*ecbbe831SMark Johnston len += 16; 175*ecbbe831SMark Johnston while ((len -= 4) >= 0) { 176*ecbbe831SMark Johnston sum += (u_int64_t) *lw++; 177*ecbbe831SMark Johnston } 178*ecbbe831SMark Johnston len += 4; 179*ecbbe831SMark Johnston if (len > 0) 180*ecbbe831SMark Johnston sum += (u_int64_t) (in_masks[len] & *lw); 181*ecbbe831SMark Johnston REDUCE32; 182*ecbbe831SMark Johnston return sum; 183*ecbbe831SMark Johnston } 184*ecbbe831SMark Johnston 185*ecbbe831SMark Johnston u_short 186*ecbbe831SMark Johnston in_addword(u_short a, u_short b) 187*ecbbe831SMark Johnston { 188*ecbbe831SMark Johnston u_int64_t sum = a + b; 189*ecbbe831SMark Johnston 190*ecbbe831SMark Johnston ADDCARRY(sum); 191*ecbbe831SMark Johnston return (sum); 192*ecbbe831SMark Johnston } 193*ecbbe831SMark Johnston 194*ecbbe831SMark Johnston u_short 195*ecbbe831SMark Johnston in_pseudo(u_int32_t a, u_int32_t b, u_int32_t c) 196*ecbbe831SMark Johnston { 197*ecbbe831SMark Johnston u_int64_t sum; 198*ecbbe831SMark Johnston union q_util q_util; 199*ecbbe831SMark Johnston union l_util l_util; 200*ecbbe831SMark Johnston 201*ecbbe831SMark Johnston sum = (u_int64_t) a + b + c; 202*ecbbe831SMark Johnston REDUCE16; 203*ecbbe831SMark Johnston return (sum); 204*ecbbe831SMark Johnston } 205*ecbbe831SMark Johnston 206*ecbbe831SMark Johnston u_short 207*ecbbe831SMark Johnston in_cksum_skip(struct mbuf *m, int len, int skip) 208*ecbbe831SMark Johnston { 209*ecbbe831SMark Johnston u_int64_t sum = 0; 210*ecbbe831SMark Johnston int mlen = 0; 211*ecbbe831SMark Johnston int clen = 0; 212*ecbbe831SMark Johnston caddr_t addr; 213*ecbbe831SMark Johnston union q_util q_util; 214*ecbbe831SMark Johnston union l_util l_util; 215*ecbbe831SMark Johnston 216*ecbbe831SMark Johnston len -= skip; 217*ecbbe831SMark Johnston for (; skip && m; m = m->m_next) { 218*ecbbe831SMark Johnston if (m->m_len > skip) { 219*ecbbe831SMark Johnston mlen = m->m_len - skip; 220*ecbbe831SMark Johnston addr = mtod(m, caddr_t) + skip; 221*ecbbe831SMark Johnston goto skip_start; 222*ecbbe831SMark Johnston } else { 223*ecbbe831SMark Johnston skip -= m->m_len; 224*ecbbe831SMark Johnston } 225*ecbbe831SMark Johnston } 226*ecbbe831SMark Johnston 227*ecbbe831SMark Johnston for (; m && len; m = m->m_next) { 228*ecbbe831SMark Johnston if (m->m_len == 0) 229*ecbbe831SMark Johnston continue; 230*ecbbe831SMark Johnston mlen = m->m_len; 231*ecbbe831SMark Johnston addr = mtod(m, caddr_t); 232*ecbbe831SMark Johnston skip_start: 233*ecbbe831SMark Johnston if (len < mlen) 234*ecbbe831SMark Johnston mlen = len; 235*ecbbe831SMark Johnston 236*ecbbe831SMark Johnston if ((clen ^ (uintptr_t) addr) & 1) 237*ecbbe831SMark Johnston sum += in_cksumdata(addr, mlen) << 8; 238*ecbbe831SMark Johnston else 239*ecbbe831SMark Johnston sum += in_cksumdata(addr, mlen); 240*ecbbe831SMark Johnston 241*ecbbe831SMark Johnston clen += mlen; 242*ecbbe831SMark Johnston len -= mlen; 243*ecbbe831SMark Johnston } 244*ecbbe831SMark Johnston REDUCE16; 245*ecbbe831SMark Johnston return (~sum & 0xffff); 246*ecbbe831SMark Johnston } 247*ecbbe831SMark Johnston 248*ecbbe831SMark Johnston u_int in_cksum_hdr(const struct ip *ip) 249*ecbbe831SMark Johnston { 250*ecbbe831SMark Johnston u_int64_t sum = in_cksumdata(ip, sizeof(struct ip)); 251*ecbbe831SMark Johnston union q_util q_util; 252*ecbbe831SMark Johnston union l_util l_util; 253*ecbbe831SMark Johnston REDUCE16; 254*ecbbe831SMark Johnston return (~sum & 0xffff); 255*ecbbe831SMark Johnston } 256*ecbbe831SMark Johnston 257*ecbbe831SMark Johnston #endif /* !HAVE_MD_IN_CKSUM */ 258