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