in6_cksum.c revision 215956
1239400Sandreast/*- 2239400Sandreast * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3239400Sandreast * All rights reserved. 4239400Sandreast * 5239400Sandreast * Redistribution and use in source and binary forms, with or without 6239400Sandreast * modification, are permitted provided that the following conditions 7239400Sandreast * are met: 8239400Sandreast * 1. Redistributions of source code must retain the above copyright 9239400Sandreast * notice, this list of conditions and the following disclaimer. 10239400Sandreast * 2. Redistributions in binary form must reproduce the above copyright 11239400Sandreast * notice, this list of conditions and the following disclaimer in the 12239400Sandreast * documentation and/or other materials provided with the distribution. 13239400Sandreast * 3. Neither the name of the project nor the names of its contributors 14239400Sandreast * may be used to endorse or promote products derived from this software 15239400Sandreast * without specific prior written permission. 16239400Sandreast * 17239400Sandreast * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18239400Sandreast * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19239400Sandreast * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20239400Sandreast * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21239400Sandreast * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22239400Sandreast * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23239400Sandreast * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24239400Sandreast * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25239400Sandreast * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26239400Sandreast * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27239400Sandreast * SUCH DAMAGE. 28239400Sandreast * 29239400Sandreast * $KAME: in6_cksum.c,v 1.10 2000/12/03 00:53:59 itojun Exp $ 30239400Sandreast */ 31239400Sandreast 32239400Sandreast/*- 33239400Sandreast * Copyright (c) 1988, 1992, 1993 34239400Sandreast * The Regents of the University of California. All rights reserved. 35239400Sandreast * 36239400Sandreast * Redistribution and use in source and binary forms, with or without 37239400Sandreast * modification, are permitted provided that the following conditions 38239400Sandreast * are met: 39239400Sandreast * 1. Redistributions of source code must retain the above copyright 40239400Sandreast * notice, this list of conditions and the following disclaimer. 41239400Sandreast * 2. Redistributions in binary form must reproduce the above copyright 42239400Sandreast * notice, this list of conditions and the following disclaimer in the 43239400Sandreast * documentation and/or other materials provided with the distribution. 44239400Sandreast * 4. Neither the name of the University nor the names of its contributors 45239400Sandreast * may be used to endorse or promote products derived from this software 46239400Sandreast * without specific prior written permission. 47239400Sandreast * 48239400Sandreast * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49239400Sandreast * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50239400Sandreast * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51239400Sandreast * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52239400Sandreast * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53239400Sandreast * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54239400Sandreast * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55239400Sandreast * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56239400Sandreast * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57239400Sandreast * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58239400Sandreast * SUCH DAMAGE. 59239400Sandreast * 60239400Sandreast * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 61239400Sandreast */ 62239400Sandreast 63239400Sandreast#include <sys/cdefs.h> 64239400Sandreast__FBSDID("$FreeBSD: head/sys/netinet6/in6_cksum.c 215956 2010-11-27 21:51:39Z brucec $"); 65239400Sandreast 66239400Sandreast#include <sys/param.h> 67239400Sandreast#include <sys/mbuf.h> 68239400Sandreast#include <sys/systm.h> 69239400Sandreast#include <netinet/in.h> 70239400Sandreast#include <netinet/ip6.h> 71239400Sandreast#include <netinet6/scope6_var.h> 72239400Sandreast 73239400Sandreast/* 74239400Sandreast * Checksum routine for Internet Protocol family headers (Portable Version). 75239400Sandreast * 76239400Sandreast * This routine is very heavily used in the network 77239400Sandreast * code and should be modified for each CPU to be as fast as possible. 78239400Sandreast */ 79239400Sandreast 80239400Sandreast#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) 81239400Sandreast#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; (void)ADDCARRY(sum);} 82239400Sandreast 83239400Sandreast/* 84239400Sandreast * m MUST contain a contiguous IP6 header. 85239400Sandreast * off is an offset where TCP/UDP/ICMP6 header starts. 86239400Sandreast * len is a total length of a transport segment. 87239400Sandreast * (e.g. TCP header + TCP payload) 88239400Sandreast */ 89239400Sandreastint 90239400Sandreastin6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len) 91239400Sandreast{ 92239400Sandreast u_int16_t *w; 93239400Sandreast int sum = 0; 94239400Sandreast int mlen = 0; 95239400Sandreast int byte_swapped = 0; 96239400Sandreast struct ip6_hdr *ip6; 97239400Sandreast struct in6_addr in6; 98239400Sandreast union { 99239400Sandreast u_int16_t phs[4]; 100239400Sandreast struct { 101239400Sandreast u_int32_t ph_len; 102239400Sandreast u_int8_t ph_zero[3]; 103239400Sandreast u_int8_t ph_nxt; 104239400Sandreast } __packed ph; 105239400Sandreast } uph; 106239400Sandreast union { 107239400Sandreast u_int8_t c[2]; 108239400Sandreast u_int16_t s; 109239400Sandreast } s_util; 110239400Sandreast union { 111239400Sandreast u_int16_t s[2]; 112239400Sandreast u_int32_t l; 113239400Sandreast } l_util; 114239400Sandreast 115239400Sandreast /* sanity check */ 116239400Sandreast if (m->m_pkthdr.len < off + len) { 117239400Sandreast panic("in6_cksum: mbuf len (%d) < off+len (%d+%d)", 118239400Sandreast m->m_pkthdr.len, off, len); 119239400Sandreast } 120239400Sandreast 121239400Sandreast bzero(&uph, sizeof(uph)); 122239400Sandreast 123239400Sandreast /* 124239400Sandreast * First create IP6 pseudo header and calculate a summary. 125239400Sandreast */ 126239400Sandreast ip6 = mtod(m, struct ip6_hdr *); 127239400Sandreast uph.ph.ph_len = htonl(len); 128239400Sandreast uph.ph.ph_nxt = nxt; 129239400Sandreast 130239400Sandreast /* 131239400Sandreast * IPv6 source address. 132239400Sandreast * XXX: we'd like to avoid copying the address, but we can't due to 133239400Sandreast * the possibly embedded scope zone ID. 134239400Sandreast */ 135239400Sandreast in6 = ip6->ip6_src; 136239400Sandreast in6_clearscope(&in6); 137239400Sandreast w = (u_int16_t *)&in6; 138239400Sandreast sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 139239400Sandreast sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 140239400Sandreast 141239400Sandreast /* IPv6 destination address */ 142239400Sandreast in6 = ip6->ip6_dst; 143239400Sandreast in6_clearscope(&in6); 144239400Sandreast w = (u_int16_t *)&in6; 145239400Sandreast sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 146239400Sandreast sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 147239400Sandreast 148239400Sandreast /* Payload length and upper layer identifier */ 149239400Sandreast sum += uph.phs[0]; sum += uph.phs[1]; 150239400Sandreast sum += uph.phs[2]; sum += uph.phs[3]; 151239400Sandreast 152239400Sandreast /* 153239400Sandreast * Secondly calculate a summary of the first mbuf excluding offset. 154239400Sandreast */ 155239400Sandreast while (off > 0) { 156239400Sandreast if (m->m_len <= off) 157239400Sandreast off -= m->m_len; 158239400Sandreast else 159239400Sandreast break; 160239400Sandreast m = m->m_next; 161239400Sandreast } 162239400Sandreast w = (u_int16_t *)(mtod(m, u_char *) + off); 163239400Sandreast mlen = m->m_len - off; 164239400Sandreast if (len < mlen) 165239400Sandreast mlen = len; 166239400Sandreast len -= mlen; 167239400Sandreast /* 168239400Sandreast * Force to even boundary. 169239400Sandreast */ 170239400Sandreast if ((1 & (long) w) && (mlen > 0)) { 171239400Sandreast REDUCE; 172239400Sandreast sum <<= 8; 173239400Sandreast s_util.c[0] = *(u_char *)w; 174239400Sandreast w = (u_int16_t *)((char *)w + 1); 175239400Sandreast mlen--; 176239400Sandreast byte_swapped = 1; 177239400Sandreast } 178239400Sandreast /* 179239400Sandreast * Unroll the loop to make overhead from 180239400Sandreast * branches &c small. 181239400Sandreast */ 182239400Sandreast while ((mlen -= 32) >= 0) { 183239400Sandreast sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 184239400Sandreast sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 185239400Sandreast sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 186239400Sandreast sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 187239400Sandreast w += 16; 188239400Sandreast } 189239400Sandreast mlen += 32; 190239400Sandreast while ((mlen -= 8) >= 0) { 191239400Sandreast sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 192239400Sandreast w += 4; 193239400Sandreast } 194239400Sandreast mlen += 8; 195239400Sandreast if (mlen == 0 && byte_swapped == 0) 196239400Sandreast goto next; 197239400Sandreast REDUCE; 198239400Sandreast while ((mlen -= 2) >= 0) { 199239400Sandreast sum += *w++; 200239400Sandreast } 201239400Sandreast if (byte_swapped) { 202239400Sandreast REDUCE; 203239400Sandreast sum <<= 8; 204239400Sandreast byte_swapped = 0; 205239400Sandreast if (mlen == -1) { 206239400Sandreast s_util.c[1] = *(char *)w; 207239400Sandreast sum += s_util.s; 208239400Sandreast mlen = 0; 209239400Sandreast } else 210239400Sandreast mlen = -1; 211239400Sandreast } else if (mlen == -1) 212239400Sandreast s_util.c[0] = *(char *)w; 213239400Sandreast next: 214239400Sandreast m = m->m_next; 215239400Sandreast 216239400Sandreast /* 217239400Sandreast * Lastly calculate a summary of the rest of mbufs. 218239400Sandreast */ 219239400Sandreast 220239400Sandreast for (;m && len; m = m->m_next) { 221239400Sandreast if (m->m_len == 0) 222239400Sandreast continue; 223239400Sandreast w = mtod(m, u_int16_t *); 224239400Sandreast if (mlen == -1) { 225239400Sandreast /* 226239400Sandreast * The first byte of this mbuf is the continuation 227239400Sandreast * of a word spanning between this mbuf and the 228239400Sandreast * last mbuf. 229239400Sandreast * 230239400Sandreast * s_util.c[0] is already saved when scanning previous 231239400Sandreast * mbuf. 232239400Sandreast */ 233239400Sandreast s_util.c[1] = *(char *)w; 234239400Sandreast sum += s_util.s; 235239400Sandreast w = (u_int16_t *)((char *)w + 1); 236239400Sandreast mlen = m->m_len - 1; 237239400Sandreast len--; 238239400Sandreast } else 239239400Sandreast mlen = m->m_len; 240239400Sandreast if (len < mlen) 241239400Sandreast mlen = len; 242239400Sandreast len -= mlen; 243239400Sandreast /* 244239400Sandreast * Force to even boundary. 245239400Sandreast */ 246239400Sandreast if ((1 & (long) w) && (mlen > 0)) { 247239400Sandreast REDUCE; 248239400Sandreast sum <<= 8; 249239400Sandreast s_util.c[0] = *(u_char *)w; 250239400Sandreast w = (u_int16_t *)((char *)w + 1); 251239400Sandreast mlen--; 252239400Sandreast byte_swapped = 1; 253239400Sandreast } 254239400Sandreast /* 255239400Sandreast * Unroll the loop to make overhead from 256239400Sandreast * branches &c small. 257239400Sandreast */ 258239400Sandreast while ((mlen -= 32) >= 0) { 259239400Sandreast sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 260239400Sandreast sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 261239400Sandreast sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 262239400Sandreast sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 263239400Sandreast w += 16; 264239400Sandreast } 265239400Sandreast mlen += 32; 266239400Sandreast while ((mlen -= 8) >= 0) { 267239400Sandreast sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 268239400Sandreast w += 4; 269239400Sandreast } 270239400Sandreast mlen += 8; 271239400Sandreast if (mlen == 0 && byte_swapped == 0) 272239400Sandreast continue; 273239400Sandreast REDUCE; 274239400Sandreast while ((mlen -= 2) >= 0) { 275239400Sandreast sum += *w++; 276239400Sandreast } 277239400Sandreast if (byte_swapped) { 278239400Sandreast REDUCE; 279239400Sandreast sum <<= 8; 280239400Sandreast byte_swapped = 0; 281239400Sandreast if (mlen == -1) { 282239400Sandreast s_util.c[1] = *(char *)w; 283239400Sandreast sum += s_util.s; 284239400Sandreast mlen = 0; 285239400Sandreast } else 286239400Sandreast mlen = -1; 287239400Sandreast } else if (mlen == -1) 288239400Sandreast s_util.c[0] = *(char *)w; 289239400Sandreast } 290239400Sandreast if (len) 291239400Sandreast panic("in6_cksum: out of data"); 292239400Sandreast if (mlen == -1) { 293239400Sandreast /* The last mbuf has odd # of bytes. Follow the 294239400Sandreast standard (the odd byte may be shifted left by 8 bits 295239400Sandreast or not as determined by endian-ness of the machine) */ 296239400Sandreast s_util.c[1] = 0; 297239400Sandreast sum += s_util.s; 298239400Sandreast } 299239400Sandreast REDUCE; 300239400Sandreast return (~sum & 0xffff); 301239400Sandreast} 302239400Sandreast