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 83*ecade87eSBjoern A. Zeeb static int 84*ecade87eSBjoern A. Zeeb _in6_cksum_pseudo(struct ip6_hdr *ip6, uint32_t len, uint8_t nxt, uint16_t csum) 85*ecade87eSBjoern A. Zeeb { 86*ecade87eSBjoern A. Zeeb int sum; 87*ecade87eSBjoern A. Zeeb uint16_t scope, *w; 88*ecade87eSBjoern A. Zeeb union { 89*ecade87eSBjoern A. Zeeb u_int16_t phs[4]; 90*ecade87eSBjoern A. Zeeb struct { 91*ecade87eSBjoern A. Zeeb u_int32_t ph_len; 92*ecade87eSBjoern A. Zeeb u_int8_t ph_zero[3]; 93*ecade87eSBjoern A. Zeeb u_int8_t ph_nxt; 94*ecade87eSBjoern A. Zeeb } __packed ph; 95*ecade87eSBjoern A. Zeeb } uph; 96*ecade87eSBjoern A. Zeeb 97*ecade87eSBjoern A. Zeeb sum = csum; 98*ecade87eSBjoern A. Zeeb 99*ecade87eSBjoern A. Zeeb /* 100*ecade87eSBjoern A. Zeeb * First create IP6 pseudo header and calculate a summary. 101*ecade87eSBjoern A. Zeeb */ 102*ecade87eSBjoern A. Zeeb uph.ph.ph_len = htonl(len); 103*ecade87eSBjoern A. Zeeb uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0; 104*ecade87eSBjoern A. Zeeb uph.ph.ph_nxt = nxt; 105*ecade87eSBjoern A. Zeeb 106*ecade87eSBjoern A. Zeeb /* Payload length and upper layer identifier. */ 107*ecade87eSBjoern A. Zeeb sum += uph.phs[0]; sum += uph.phs[1]; 108*ecade87eSBjoern A. Zeeb sum += uph.phs[2]; sum += uph.phs[3]; 109*ecade87eSBjoern A. Zeeb 110*ecade87eSBjoern A. Zeeb /* IPv6 source address. */ 111*ecade87eSBjoern A. Zeeb scope = in6_getscope(&ip6->ip6_src); 112*ecade87eSBjoern A. Zeeb w = (u_int16_t *)&ip6->ip6_src; 113*ecade87eSBjoern A. Zeeb sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 114*ecade87eSBjoern A. Zeeb sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 115*ecade87eSBjoern A. Zeeb if (scope != 0) 116*ecade87eSBjoern A. Zeeb sum -= scope; 117*ecade87eSBjoern A. Zeeb 118*ecade87eSBjoern A. Zeeb /* IPv6 destination address. */ 119*ecade87eSBjoern A. Zeeb scope = in6_getscope(&ip6->ip6_dst); 120*ecade87eSBjoern A. Zeeb w = (u_int16_t *)&ip6->ip6_dst; 121*ecade87eSBjoern A. Zeeb sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 122*ecade87eSBjoern A. Zeeb sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 123*ecade87eSBjoern A. Zeeb if (scope != 0) 124*ecade87eSBjoern A. Zeeb sum -= scope; 125*ecade87eSBjoern A. Zeeb 126*ecade87eSBjoern A. Zeeb return (sum); 127*ecade87eSBjoern A. Zeeb } 128*ecade87eSBjoern A. Zeeb 129*ecade87eSBjoern A. Zeeb int 130*ecade87eSBjoern A. Zeeb in6_cksum_pseudo(struct ip6_hdr *ip6, uint32_t len, uint8_t nxt, uint16_t csum) 131*ecade87eSBjoern A. Zeeb { 132*ecade87eSBjoern A. Zeeb int sum; 133*ecade87eSBjoern A. Zeeb union { 134*ecade87eSBjoern A. Zeeb u_int16_t s[2]; 135*ecade87eSBjoern A. Zeeb u_int32_t l; 136*ecade87eSBjoern A. Zeeb } l_util; 137*ecade87eSBjoern A. Zeeb 138*ecade87eSBjoern A. Zeeb sum = _in6_cksum_pseudo(ip6, len, nxt, csum); 139*ecade87eSBjoern A. Zeeb REDUCE; 140*ecade87eSBjoern A. Zeeb return (sum); 141*ecade87eSBjoern A. Zeeb } 142*ecade87eSBjoern A. Zeeb 14382cd038dSYoshinobu Inoue /* 1446d79f3f6SRebecca Cran * m MUST contain a contiguous IP6 header. 1459d5abbddSJens Schweikhardt * off is an offset where TCP/UDP/ICMP6 header starts. 14682cd038dSYoshinobu Inoue * len is a total length of a transport segment. 14782cd038dSYoshinobu Inoue * (e.g. TCP header + TCP payload) 14882cd038dSYoshinobu Inoue */ 14982cd038dSYoshinobu Inoue int 1509f8a02f1SRobert Watson in6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len) 15182cd038dSYoshinobu Inoue { 15282cd038dSYoshinobu Inoue struct ip6_hdr *ip6; 1532889eb8bSBjoern A. Zeeb u_int16_t *w, scope; 1542889eb8bSBjoern A. Zeeb int byte_swapped, mlen; 1552889eb8bSBjoern A. Zeeb int sum; 15629a3d1b0SJun-ichiro itojun Hagino union { 15729a3d1b0SJun-ichiro itojun Hagino u_int16_t phs[4]; 15829a3d1b0SJun-ichiro itojun Hagino struct { 15929a3d1b0SJun-ichiro itojun Hagino u_int32_t ph_len; 16029a3d1b0SJun-ichiro itojun Hagino u_int8_t ph_zero[3]; 16129a3d1b0SJun-ichiro itojun Hagino u_int8_t ph_nxt; 1621c0ee39eSWarner Losh } __packed ph; 16329a3d1b0SJun-ichiro itojun Hagino } uph; 16482cd038dSYoshinobu Inoue union { 16582cd038dSYoshinobu Inoue u_int8_t c[2]; 16682cd038dSYoshinobu Inoue u_int16_t s; 16782cd038dSYoshinobu Inoue } s_util; 16882cd038dSYoshinobu Inoue union { 16982cd038dSYoshinobu Inoue u_int16_t s[2]; 17082cd038dSYoshinobu Inoue u_int32_t l; 17182cd038dSYoshinobu Inoue } l_util; 17282cd038dSYoshinobu Inoue 1732889eb8bSBjoern A. Zeeb /* Sanity check. */ 1742889eb8bSBjoern A. Zeeb KASSERT(m->m_pkthdr.len >= off + len, ("%s: mbuf len (%d) < off(%d)+" 1752889eb8bSBjoern A. Zeeb "len(%d)", __func__, m->m_pkthdr.len, off, len)); 17629a3d1b0SJun-ichiro itojun Hagino 17782cd038dSYoshinobu Inoue /* 17882cd038dSYoshinobu Inoue * First create IP6 pseudo header and calculate a summary. 17982cd038dSYoshinobu Inoue */ 18082cd038dSYoshinobu Inoue uph.ph.ph_len = htonl(len); 1812889eb8bSBjoern A. Zeeb uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0; 18282cd038dSYoshinobu Inoue uph.ph.ph_nxt = nxt; 18382cd038dSYoshinobu Inoue 1842889eb8bSBjoern A. Zeeb /* Payload length and upper layer identifier. */ 1852889eb8bSBjoern A. Zeeb sum = uph.phs[0]; sum += uph.phs[1]; 18682cd038dSYoshinobu Inoue sum += uph.phs[2]; sum += uph.phs[3]; 18782cd038dSYoshinobu Inoue 1882889eb8bSBjoern A. Zeeb ip6 = mtod(m, struct ip6_hdr *); 1892889eb8bSBjoern A. Zeeb 1902889eb8bSBjoern A. Zeeb /* IPv6 source address. */ 1912889eb8bSBjoern A. Zeeb scope = in6_getscope(&ip6->ip6_src); 1922889eb8bSBjoern A. Zeeb w = (u_int16_t *)&ip6->ip6_src; 1932889eb8bSBjoern A. Zeeb sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 1942889eb8bSBjoern A. Zeeb sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 1952889eb8bSBjoern A. Zeeb if (scope != 0) 1962889eb8bSBjoern A. Zeeb sum -= scope; 1972889eb8bSBjoern A. Zeeb 1982889eb8bSBjoern A. Zeeb /* IPv6 destination address. */ 1992889eb8bSBjoern A. Zeeb scope = in6_getscope(&ip6->ip6_dst); 2002889eb8bSBjoern A. Zeeb w = (u_int16_t *)&ip6->ip6_dst; 2012889eb8bSBjoern A. Zeeb sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 2022889eb8bSBjoern A. Zeeb sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 2032889eb8bSBjoern A. Zeeb if (scope != 0) 2042889eb8bSBjoern A. Zeeb sum -= scope; 2052889eb8bSBjoern A. Zeeb 20682cd038dSYoshinobu Inoue /* 20782cd038dSYoshinobu Inoue * Secondly calculate a summary of the first mbuf excluding offset. 20882cd038dSYoshinobu Inoue */ 2094e6098c6SYaroslav Tykhiy while (off > 0) { 21082cd038dSYoshinobu Inoue if (m->m_len <= off) 21182cd038dSYoshinobu Inoue off -= m->m_len; 21282cd038dSYoshinobu Inoue else 21382cd038dSYoshinobu Inoue break; 21482cd038dSYoshinobu Inoue m = m->m_next; 21582cd038dSYoshinobu Inoue } 21682cd038dSYoshinobu Inoue w = (u_int16_t *)(mtod(m, u_char *) + off); 21782cd038dSYoshinobu Inoue mlen = m->m_len - off; 21882cd038dSYoshinobu Inoue if (len < mlen) 21982cd038dSYoshinobu Inoue mlen = len; 22082cd038dSYoshinobu Inoue len -= mlen; 22182cd038dSYoshinobu Inoue /* 22282cd038dSYoshinobu Inoue * Force to even boundary. 22382cd038dSYoshinobu Inoue */ 22482cd038dSYoshinobu Inoue if ((1 & (long)w) && (mlen > 0)) { 22582cd038dSYoshinobu Inoue REDUCE; 22682cd038dSYoshinobu Inoue sum <<= 8; 22782cd038dSYoshinobu Inoue s_util.c[0] = *(u_char *)w; 22882cd038dSYoshinobu Inoue w = (u_int16_t *)((char *)w + 1); 22982cd038dSYoshinobu Inoue mlen--; 23082cd038dSYoshinobu Inoue byte_swapped = 1; 2312889eb8bSBjoern A. Zeeb } else 2322889eb8bSBjoern A. Zeeb byte_swapped = 0; 2332889eb8bSBjoern A. Zeeb 23482cd038dSYoshinobu Inoue /* 23582cd038dSYoshinobu Inoue * Unroll the loop to make overhead from 23682cd038dSYoshinobu Inoue * branches &c small. 23782cd038dSYoshinobu Inoue */ 23882cd038dSYoshinobu Inoue while ((mlen -= 32) >= 0) { 23982cd038dSYoshinobu Inoue sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 24082cd038dSYoshinobu Inoue sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 24182cd038dSYoshinobu Inoue sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 24282cd038dSYoshinobu Inoue sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 24382cd038dSYoshinobu Inoue w += 16; 24482cd038dSYoshinobu Inoue } 24582cd038dSYoshinobu Inoue mlen += 32; 24682cd038dSYoshinobu Inoue while ((mlen -= 8) >= 0) { 24782cd038dSYoshinobu Inoue sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 24882cd038dSYoshinobu Inoue w += 4; 24982cd038dSYoshinobu Inoue } 25082cd038dSYoshinobu Inoue mlen += 8; 25182cd038dSYoshinobu Inoue if (mlen == 0 && byte_swapped == 0) 25282cd038dSYoshinobu Inoue goto next; 25382cd038dSYoshinobu Inoue REDUCE; 25482cd038dSYoshinobu Inoue while ((mlen -= 2) >= 0) { 25582cd038dSYoshinobu Inoue sum += *w++; 25682cd038dSYoshinobu Inoue } 25782cd038dSYoshinobu Inoue if (byte_swapped) { 25882cd038dSYoshinobu Inoue REDUCE; 25982cd038dSYoshinobu Inoue sum <<= 8; 26082cd038dSYoshinobu Inoue byte_swapped = 0; 26182cd038dSYoshinobu Inoue if (mlen == -1) { 26282cd038dSYoshinobu Inoue s_util.c[1] = *(char *)w; 26382cd038dSYoshinobu Inoue sum += s_util.s; 26482cd038dSYoshinobu Inoue mlen = 0; 26582cd038dSYoshinobu Inoue } else 26682cd038dSYoshinobu Inoue mlen = -1; 26782cd038dSYoshinobu Inoue } else if (mlen == -1) 26882cd038dSYoshinobu Inoue s_util.c[0] = *(char *)w; 26982cd038dSYoshinobu Inoue next: 27082cd038dSYoshinobu Inoue m = m->m_next; 27182cd038dSYoshinobu Inoue 27282cd038dSYoshinobu Inoue /* 27382cd038dSYoshinobu Inoue * Lastly calculate a summary of the rest of mbufs. 27482cd038dSYoshinobu Inoue */ 27582cd038dSYoshinobu Inoue 27682cd038dSYoshinobu Inoue for (;m && len; m = m->m_next) { 27782cd038dSYoshinobu Inoue if (m->m_len == 0) 27882cd038dSYoshinobu Inoue continue; 27982cd038dSYoshinobu Inoue w = mtod(m, u_int16_t *); 28082cd038dSYoshinobu Inoue if (mlen == -1) { 28182cd038dSYoshinobu Inoue /* 28282cd038dSYoshinobu Inoue * The first byte of this mbuf is the continuation 28382cd038dSYoshinobu Inoue * of a word spanning between this mbuf and the 28482cd038dSYoshinobu Inoue * last mbuf. 28582cd038dSYoshinobu Inoue * 28682cd038dSYoshinobu Inoue * s_util.c[0] is already saved when scanning previous 28782cd038dSYoshinobu Inoue * mbuf. 28882cd038dSYoshinobu Inoue */ 28982cd038dSYoshinobu Inoue s_util.c[1] = *(char *)w; 29082cd038dSYoshinobu Inoue sum += s_util.s; 29182cd038dSYoshinobu Inoue w = (u_int16_t *)((char *)w + 1); 29282cd038dSYoshinobu Inoue mlen = m->m_len - 1; 29382cd038dSYoshinobu Inoue len--; 29482cd038dSYoshinobu Inoue } else 29582cd038dSYoshinobu Inoue mlen = m->m_len; 29682cd038dSYoshinobu Inoue if (len < mlen) 29782cd038dSYoshinobu Inoue mlen = len; 29882cd038dSYoshinobu Inoue len -= mlen; 29982cd038dSYoshinobu Inoue /* 30082cd038dSYoshinobu Inoue * Force to even boundary. 30182cd038dSYoshinobu Inoue */ 30282cd038dSYoshinobu Inoue if ((1 & (long) w) && (mlen > 0)) { 30382cd038dSYoshinobu Inoue REDUCE; 30482cd038dSYoshinobu Inoue sum <<= 8; 30582cd038dSYoshinobu Inoue s_util.c[0] = *(u_char *)w; 30682cd038dSYoshinobu Inoue w = (u_int16_t *)((char *)w + 1); 30782cd038dSYoshinobu Inoue mlen--; 30882cd038dSYoshinobu Inoue byte_swapped = 1; 30982cd038dSYoshinobu Inoue } 31082cd038dSYoshinobu Inoue /* 31182cd038dSYoshinobu Inoue * Unroll the loop to make overhead from 31282cd038dSYoshinobu Inoue * branches &c small. 31382cd038dSYoshinobu Inoue */ 31482cd038dSYoshinobu Inoue while ((mlen -= 32) >= 0) { 31582cd038dSYoshinobu Inoue sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 31682cd038dSYoshinobu Inoue sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 31782cd038dSYoshinobu Inoue sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 31882cd038dSYoshinobu Inoue sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 31982cd038dSYoshinobu Inoue w += 16; 32082cd038dSYoshinobu Inoue } 32182cd038dSYoshinobu Inoue mlen += 32; 32282cd038dSYoshinobu Inoue while ((mlen -= 8) >= 0) { 32382cd038dSYoshinobu Inoue sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 32482cd038dSYoshinobu Inoue w += 4; 32582cd038dSYoshinobu Inoue } 32682cd038dSYoshinobu Inoue mlen += 8; 32782cd038dSYoshinobu Inoue if (mlen == 0 && byte_swapped == 0) 32882cd038dSYoshinobu Inoue continue; 32982cd038dSYoshinobu Inoue REDUCE; 33082cd038dSYoshinobu Inoue while ((mlen -= 2) >= 0) { 33182cd038dSYoshinobu Inoue sum += *w++; 33282cd038dSYoshinobu Inoue } 33382cd038dSYoshinobu Inoue if (byte_swapped) { 33482cd038dSYoshinobu Inoue REDUCE; 33582cd038dSYoshinobu Inoue sum <<= 8; 33682cd038dSYoshinobu Inoue byte_swapped = 0; 33782cd038dSYoshinobu Inoue if (mlen == -1) { 33882cd038dSYoshinobu Inoue s_util.c[1] = *(char *)w; 33982cd038dSYoshinobu Inoue sum += s_util.s; 34082cd038dSYoshinobu Inoue mlen = 0; 34182cd038dSYoshinobu Inoue } else 34282cd038dSYoshinobu Inoue mlen = -1; 34382cd038dSYoshinobu Inoue } else if (mlen == -1) 34482cd038dSYoshinobu Inoue s_util.c[0] = *(char *)w; 34582cd038dSYoshinobu Inoue } 34682cd038dSYoshinobu Inoue if (len) 34777d43daeSSUZUKI Shinsuke panic("in6_cksum: out of data"); 34882cd038dSYoshinobu Inoue if (mlen == -1) { 34982cd038dSYoshinobu Inoue /* The last mbuf has odd # of bytes. Follow the 35082cd038dSYoshinobu Inoue standard (the odd byte may be shifted left by 8 bits 35182cd038dSYoshinobu Inoue or not as determined by endian-ness of the machine) */ 35282cd038dSYoshinobu Inoue s_util.c[1] = 0; 35382cd038dSYoshinobu Inoue sum += s_util.s; 35482cd038dSYoshinobu Inoue } 35582cd038dSYoshinobu Inoue REDUCE; 35682cd038dSYoshinobu Inoue return (~sum & 0xffff); 35782cd038dSYoshinobu Inoue } 358