1caf43b02SWarner Losh /*- 282cd038dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 382cd038dSYoshinobu Inoue * All rights reserved. 482cd038dSYoshinobu Inoue * 582cd038dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 682cd038dSYoshinobu Inoue * modification, are permitted provided that the following conditions 782cd038dSYoshinobu Inoue * are met: 882cd038dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 982cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 1082cd038dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 1182cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 1282cd038dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 1382cd038dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 1482cd038dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 1582cd038dSYoshinobu Inoue * without specific prior written permission. 1682cd038dSYoshinobu Inoue * 1782cd038dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1882cd038dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1982cd038dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2082cd038dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2182cd038dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2282cd038dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2382cd038dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2482cd038dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2582cd038dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2682cd038dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2782cd038dSYoshinobu Inoue * SUCH DAMAGE. 28b48287a3SDavid E. O'Brien * 29b48287a3SDavid E. O'Brien * $KAME: in6_cksum.c,v 1.10 2000/12/03 00:53:59 itojun Exp $ 3082cd038dSYoshinobu Inoue */ 3182cd038dSYoshinobu Inoue 32caf43b02SWarner Losh /*- 3382cd038dSYoshinobu Inoue * Copyright (c) 1988, 1992, 1993 3482cd038dSYoshinobu Inoue * The Regents of the University of California. All rights reserved. 3582cd038dSYoshinobu Inoue * 3682cd038dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 3782cd038dSYoshinobu Inoue * modification, are permitted provided that the following conditions 3882cd038dSYoshinobu Inoue * are met: 3982cd038dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 4082cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 4182cd038dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 4282cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 4382cd038dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 4482cd038dSYoshinobu Inoue * 4. Neither the name of the University nor the names of its contributors 4582cd038dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 4682cd038dSYoshinobu Inoue * without specific prior written permission. 4782cd038dSYoshinobu Inoue * 4882cd038dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 4982cd038dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5082cd038dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5182cd038dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5282cd038dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5382cd038dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5482cd038dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5582cd038dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5682cd038dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5782cd038dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5882cd038dSYoshinobu Inoue * SUCH DAMAGE. 5982cd038dSYoshinobu Inoue * 6082cd038dSYoshinobu Inoue * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 6182cd038dSYoshinobu Inoue */ 6282cd038dSYoshinobu Inoue 63b48287a3SDavid E. O'Brien #include <sys/cdefs.h> 64b48287a3SDavid E. O'Brien __FBSDID("$FreeBSD$"); 65b48287a3SDavid E. O'Brien 6682cd038dSYoshinobu Inoue #include <sys/param.h> 6782cd038dSYoshinobu Inoue #include <sys/mbuf.h> 6882cd038dSYoshinobu Inoue #include <sys/systm.h> 6982cd038dSYoshinobu Inoue #include <netinet/in.h> 70686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h> 71a1f7e5f8SHajimu UMEMOTO #include <netinet6/scope6_var.h> 7282cd038dSYoshinobu Inoue 7382cd038dSYoshinobu Inoue /* 7482cd038dSYoshinobu Inoue * Checksum routine for Internet Protocol family headers (Portable Version). 7582cd038dSYoshinobu Inoue * 7682cd038dSYoshinobu Inoue * This routine is very heavily used in the network 7782cd038dSYoshinobu Inoue * code and should be modified for each CPU to be as fast as possible. 7882cd038dSYoshinobu Inoue */ 7982cd038dSYoshinobu Inoue 8082cd038dSYoshinobu Inoue #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) 814c888125SRui Paulo #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; (void)ADDCARRY(sum);} 8282cd038dSYoshinobu Inoue 8382cd038dSYoshinobu Inoue /* 846d79f3f6SRebecca Cran * m MUST contain a contiguous IP6 header. 859d5abbddSJens Schweikhardt * off is an offset where TCP/UDP/ICMP6 header starts. 8682cd038dSYoshinobu Inoue * len is a total length of a transport segment. 8782cd038dSYoshinobu Inoue * (e.g. TCP header + TCP payload) 8882cd038dSYoshinobu Inoue */ 8982cd038dSYoshinobu Inoue int 909f8a02f1SRobert Watson in6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len) 9182cd038dSYoshinobu Inoue { 9282cd038dSYoshinobu Inoue struct ip6_hdr *ip6; 93*2889eb8bSBjoern A. Zeeb u_int16_t *w, scope; 94*2889eb8bSBjoern A. Zeeb int byte_swapped, mlen; 95*2889eb8bSBjoern A. Zeeb int sum; 9629a3d1b0SJun-ichiro itojun Hagino union { 9729a3d1b0SJun-ichiro itojun Hagino u_int16_t phs[4]; 9829a3d1b0SJun-ichiro itojun Hagino struct { 9929a3d1b0SJun-ichiro itojun Hagino u_int32_t ph_len; 10029a3d1b0SJun-ichiro itojun Hagino u_int8_t ph_zero[3]; 10129a3d1b0SJun-ichiro itojun Hagino u_int8_t ph_nxt; 1021c0ee39eSWarner Losh } __packed ph; 10329a3d1b0SJun-ichiro itojun Hagino } uph; 10482cd038dSYoshinobu Inoue union { 10582cd038dSYoshinobu Inoue u_int8_t c[2]; 10682cd038dSYoshinobu Inoue u_int16_t s; 10782cd038dSYoshinobu Inoue } s_util; 10882cd038dSYoshinobu Inoue union { 10982cd038dSYoshinobu Inoue u_int16_t s[2]; 11082cd038dSYoshinobu Inoue u_int32_t l; 11182cd038dSYoshinobu Inoue } l_util; 11282cd038dSYoshinobu Inoue 113*2889eb8bSBjoern A. Zeeb /* Sanity check. */ 114*2889eb8bSBjoern A. Zeeb KASSERT(m->m_pkthdr.len >= off + len, ("%s: mbuf len (%d) < off(%d)+" 115*2889eb8bSBjoern A. Zeeb "len(%d)", __func__, m->m_pkthdr.len, off, len)); 11629a3d1b0SJun-ichiro itojun Hagino 11782cd038dSYoshinobu Inoue /* 11882cd038dSYoshinobu Inoue * First create IP6 pseudo header and calculate a summary. 11982cd038dSYoshinobu Inoue */ 12082cd038dSYoshinobu Inoue uph.ph.ph_len = htonl(len); 121*2889eb8bSBjoern A. Zeeb uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0; 12282cd038dSYoshinobu Inoue uph.ph.ph_nxt = nxt; 12382cd038dSYoshinobu Inoue 124*2889eb8bSBjoern A. Zeeb /* Payload length and upper layer identifier. */ 125*2889eb8bSBjoern A. Zeeb sum = uph.phs[0]; sum += uph.phs[1]; 12682cd038dSYoshinobu Inoue sum += uph.phs[2]; sum += uph.phs[3]; 12782cd038dSYoshinobu Inoue 128*2889eb8bSBjoern A. Zeeb ip6 = mtod(m, struct ip6_hdr *); 129*2889eb8bSBjoern A. Zeeb 130*2889eb8bSBjoern A. Zeeb /* IPv6 source address. */ 131*2889eb8bSBjoern A. Zeeb scope = in6_getscope(&ip6->ip6_src); 132*2889eb8bSBjoern A. Zeeb w = (u_int16_t *)&ip6->ip6_src; 133*2889eb8bSBjoern A. Zeeb sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 134*2889eb8bSBjoern A. Zeeb sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 135*2889eb8bSBjoern A. Zeeb if (scope != 0) 136*2889eb8bSBjoern A. Zeeb sum -= scope; 137*2889eb8bSBjoern A. Zeeb 138*2889eb8bSBjoern A. Zeeb /* IPv6 destination address. */ 139*2889eb8bSBjoern A. Zeeb scope = in6_getscope(&ip6->ip6_dst); 140*2889eb8bSBjoern A. Zeeb w = (u_int16_t *)&ip6->ip6_dst; 141*2889eb8bSBjoern A. Zeeb sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 142*2889eb8bSBjoern A. Zeeb sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 143*2889eb8bSBjoern A. Zeeb if (scope != 0) 144*2889eb8bSBjoern A. Zeeb sum -= scope; 145*2889eb8bSBjoern A. Zeeb 14682cd038dSYoshinobu Inoue /* 14782cd038dSYoshinobu Inoue * Secondly calculate a summary of the first mbuf excluding offset. 14882cd038dSYoshinobu Inoue */ 1494e6098c6SYaroslav Tykhiy while (off > 0) { 15082cd038dSYoshinobu Inoue if (m->m_len <= off) 15182cd038dSYoshinobu Inoue off -= m->m_len; 15282cd038dSYoshinobu Inoue else 15382cd038dSYoshinobu Inoue break; 15482cd038dSYoshinobu Inoue m = m->m_next; 15582cd038dSYoshinobu Inoue } 15682cd038dSYoshinobu Inoue w = (u_int16_t *)(mtod(m, u_char *) + off); 15782cd038dSYoshinobu Inoue mlen = m->m_len - off; 15882cd038dSYoshinobu Inoue if (len < mlen) 15982cd038dSYoshinobu Inoue mlen = len; 16082cd038dSYoshinobu Inoue len -= mlen; 16182cd038dSYoshinobu Inoue /* 16282cd038dSYoshinobu Inoue * Force to even boundary. 16382cd038dSYoshinobu Inoue */ 16482cd038dSYoshinobu Inoue if ((1 & (long)w) && (mlen > 0)) { 16582cd038dSYoshinobu Inoue REDUCE; 16682cd038dSYoshinobu Inoue sum <<= 8; 16782cd038dSYoshinobu Inoue s_util.c[0] = *(u_char *)w; 16882cd038dSYoshinobu Inoue w = (u_int16_t *)((char *)w + 1); 16982cd038dSYoshinobu Inoue mlen--; 17082cd038dSYoshinobu Inoue byte_swapped = 1; 171*2889eb8bSBjoern A. Zeeb } else 172*2889eb8bSBjoern A. Zeeb byte_swapped = 0; 173*2889eb8bSBjoern A. Zeeb 17482cd038dSYoshinobu Inoue /* 17582cd038dSYoshinobu Inoue * Unroll the loop to make overhead from 17682cd038dSYoshinobu Inoue * branches &c small. 17782cd038dSYoshinobu Inoue */ 17882cd038dSYoshinobu Inoue while ((mlen -= 32) >= 0) { 17982cd038dSYoshinobu Inoue sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 18082cd038dSYoshinobu Inoue sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 18182cd038dSYoshinobu Inoue sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 18282cd038dSYoshinobu Inoue sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 18382cd038dSYoshinobu Inoue w += 16; 18482cd038dSYoshinobu Inoue } 18582cd038dSYoshinobu Inoue mlen += 32; 18682cd038dSYoshinobu Inoue while ((mlen -= 8) >= 0) { 18782cd038dSYoshinobu Inoue sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 18882cd038dSYoshinobu Inoue w += 4; 18982cd038dSYoshinobu Inoue } 19082cd038dSYoshinobu Inoue mlen += 8; 19182cd038dSYoshinobu Inoue if (mlen == 0 && byte_swapped == 0) 19282cd038dSYoshinobu Inoue goto next; 19382cd038dSYoshinobu Inoue REDUCE; 19482cd038dSYoshinobu Inoue while ((mlen -= 2) >= 0) { 19582cd038dSYoshinobu Inoue sum += *w++; 19682cd038dSYoshinobu Inoue } 19782cd038dSYoshinobu Inoue if (byte_swapped) { 19882cd038dSYoshinobu Inoue REDUCE; 19982cd038dSYoshinobu Inoue sum <<= 8; 20082cd038dSYoshinobu Inoue byte_swapped = 0; 20182cd038dSYoshinobu Inoue if (mlen == -1) { 20282cd038dSYoshinobu Inoue s_util.c[1] = *(char *)w; 20382cd038dSYoshinobu Inoue sum += s_util.s; 20482cd038dSYoshinobu Inoue mlen = 0; 20582cd038dSYoshinobu Inoue } else 20682cd038dSYoshinobu Inoue mlen = -1; 20782cd038dSYoshinobu Inoue } else if (mlen == -1) 20882cd038dSYoshinobu Inoue s_util.c[0] = *(char *)w; 20982cd038dSYoshinobu Inoue next: 21082cd038dSYoshinobu Inoue m = m->m_next; 21182cd038dSYoshinobu Inoue 21282cd038dSYoshinobu Inoue /* 21382cd038dSYoshinobu Inoue * Lastly calculate a summary of the rest of mbufs. 21482cd038dSYoshinobu Inoue */ 21582cd038dSYoshinobu Inoue 21682cd038dSYoshinobu Inoue for (;m && len; m = m->m_next) { 21782cd038dSYoshinobu Inoue if (m->m_len == 0) 21882cd038dSYoshinobu Inoue continue; 21982cd038dSYoshinobu Inoue w = mtod(m, u_int16_t *); 22082cd038dSYoshinobu Inoue if (mlen == -1) { 22182cd038dSYoshinobu Inoue /* 22282cd038dSYoshinobu Inoue * The first byte of this mbuf is the continuation 22382cd038dSYoshinobu Inoue * of a word spanning between this mbuf and the 22482cd038dSYoshinobu Inoue * last mbuf. 22582cd038dSYoshinobu Inoue * 22682cd038dSYoshinobu Inoue * s_util.c[0] is already saved when scanning previous 22782cd038dSYoshinobu Inoue * mbuf. 22882cd038dSYoshinobu Inoue */ 22982cd038dSYoshinobu Inoue s_util.c[1] = *(char *)w; 23082cd038dSYoshinobu Inoue sum += s_util.s; 23182cd038dSYoshinobu Inoue w = (u_int16_t *)((char *)w + 1); 23282cd038dSYoshinobu Inoue mlen = m->m_len - 1; 23382cd038dSYoshinobu Inoue len--; 23482cd038dSYoshinobu Inoue } else 23582cd038dSYoshinobu Inoue mlen = m->m_len; 23682cd038dSYoshinobu Inoue if (len < mlen) 23782cd038dSYoshinobu Inoue mlen = len; 23882cd038dSYoshinobu Inoue len -= mlen; 23982cd038dSYoshinobu Inoue /* 24082cd038dSYoshinobu Inoue * Force to even boundary. 24182cd038dSYoshinobu Inoue */ 24282cd038dSYoshinobu Inoue if ((1 & (long) w) && (mlen > 0)) { 24382cd038dSYoshinobu Inoue REDUCE; 24482cd038dSYoshinobu Inoue sum <<= 8; 24582cd038dSYoshinobu Inoue s_util.c[0] = *(u_char *)w; 24682cd038dSYoshinobu Inoue w = (u_int16_t *)((char *)w + 1); 24782cd038dSYoshinobu Inoue mlen--; 24882cd038dSYoshinobu Inoue byte_swapped = 1; 24982cd038dSYoshinobu Inoue } 25082cd038dSYoshinobu Inoue /* 25182cd038dSYoshinobu Inoue * Unroll the loop to make overhead from 25282cd038dSYoshinobu Inoue * branches &c small. 25382cd038dSYoshinobu Inoue */ 25482cd038dSYoshinobu Inoue while ((mlen -= 32) >= 0) { 25582cd038dSYoshinobu Inoue sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 25682cd038dSYoshinobu Inoue sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 25782cd038dSYoshinobu Inoue sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 25882cd038dSYoshinobu Inoue sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 25982cd038dSYoshinobu Inoue w += 16; 26082cd038dSYoshinobu Inoue } 26182cd038dSYoshinobu Inoue mlen += 32; 26282cd038dSYoshinobu Inoue while ((mlen -= 8) >= 0) { 26382cd038dSYoshinobu Inoue sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 26482cd038dSYoshinobu Inoue w += 4; 26582cd038dSYoshinobu Inoue } 26682cd038dSYoshinobu Inoue mlen += 8; 26782cd038dSYoshinobu Inoue if (mlen == 0 && byte_swapped == 0) 26882cd038dSYoshinobu Inoue continue; 26982cd038dSYoshinobu Inoue REDUCE; 27082cd038dSYoshinobu Inoue while ((mlen -= 2) >= 0) { 27182cd038dSYoshinobu Inoue sum += *w++; 27282cd038dSYoshinobu Inoue } 27382cd038dSYoshinobu Inoue if (byte_swapped) { 27482cd038dSYoshinobu Inoue REDUCE; 27582cd038dSYoshinobu Inoue sum <<= 8; 27682cd038dSYoshinobu Inoue byte_swapped = 0; 27782cd038dSYoshinobu Inoue if (mlen == -1) { 27882cd038dSYoshinobu Inoue s_util.c[1] = *(char *)w; 27982cd038dSYoshinobu Inoue sum += s_util.s; 28082cd038dSYoshinobu Inoue mlen = 0; 28182cd038dSYoshinobu Inoue } else 28282cd038dSYoshinobu Inoue mlen = -1; 28382cd038dSYoshinobu Inoue } else if (mlen == -1) 28482cd038dSYoshinobu Inoue s_util.c[0] = *(char *)w; 28582cd038dSYoshinobu Inoue } 28682cd038dSYoshinobu Inoue if (len) 28777d43daeSSUZUKI Shinsuke panic("in6_cksum: out of data"); 28882cd038dSYoshinobu Inoue if (mlen == -1) { 28982cd038dSYoshinobu Inoue /* The last mbuf has odd # of bytes. Follow the 29082cd038dSYoshinobu Inoue standard (the odd byte may be shifted left by 8 bits 29182cd038dSYoshinobu Inoue or not as determined by endian-ness of the machine) */ 29282cd038dSYoshinobu Inoue s_util.c[1] = 0; 29382cd038dSYoshinobu Inoue sum += s_util.s; 29482cd038dSYoshinobu Inoue } 29582cd038dSYoshinobu Inoue REDUCE; 29682cd038dSYoshinobu Inoue return (~sum & 0xffff); 29782cd038dSYoshinobu Inoue } 298