1129198Scognet/* $NetBSD: in_cksum.c,v 1.7 1997/09/02 13:18:15 thorpej Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (c) 1988, 1992, 1993 5129198Scognet * The Regents of the University of California. All rights reserved. 6129198Scognet * Copyright (c) 1996 7129198Scognet * Matt Thomas <matt@3am-software.com> 8129198Scognet * 9129198Scognet * Redistribution and use in source and binary forms, with or without 10129198Scognet * modification, are permitted provided that the following conditions 11129198Scognet * are met: 12129198Scognet * 1. Redistributions of source code must retain the above copyright 13129198Scognet * notice, this list of conditions and the following disclaimer. 14129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 15129198Scognet * notice, this list of conditions and the following disclaimer in the 16129198Scognet * documentation and/or other materials provided with the distribution. 17129198Scognet * 3. All advertising materials mentioning features or use of this software 18129198Scognet * must display the following acknowledgement: 19129198Scognet * This product includes software developed by the University of 20129198Scognet * California, Berkeley and its contributors. 21129198Scognet * 4. Neither the name of the University nor the names of its contributors 22129198Scognet * may be used to endorse or promote products derived from this software 23129198Scognet * without specific prior written permission. 24129198Scognet * 25129198Scognet * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26129198Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27129198Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28129198Scognet * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29129198Scognet * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30129198Scognet * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31129198Scognet * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35129198Scognet * SUCH DAMAGE. 36129198Scognet * 37129198Scognet * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 38129198Scognet */ 39129198Scognet 40129198Scognet#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 41129198Scognet__FBSDID("$FreeBSD$"); 42129198Scognet 43129198Scognet#include <sys/param.h> 44129198Scognet#include <sys/mbuf.h> 45129198Scognet#include <sys/systm.h> 46129198Scognet#include <netinet/in_systm.h> 47129198Scognet#include <netinet/in.h> 48129198Scognet#include <netinet/ip.h> 49129198Scognet#include <machine/in_cksum.h> 50129198Scognet 51129198Scognet/* 52129198Scognet * Checksum routine for Internet Protocol family headers 53129198Scognet * (Portable Alpha version). 54129198Scognet * 55129198Scognet * This routine is very heavily used in the network 56129198Scognet * code and should be modified for each CPU to be as fast as possible. 57129198Scognet */ 58129198Scognet 59129198Scognet#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) 60129198Scognet#define REDUCE32 \ 61129198Scognet { \ 62129198Scognet q_util.q = sum; \ 63129198Scognet sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \ 64129198Scognet } 65129198Scognet#define REDUCE16 \ 66129198Scognet { \ 67129198Scognet q_util.q = sum; \ 68129198Scognet l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \ 69129198Scognet sum = l_util.s[0] + l_util.s[1]; \ 70129198Scognet ADDCARRY(sum); \ 71129198Scognet } 72129198Scognet 73129198Scognetunion l_util { 74129198Scognet u_int16_t s[2]; 75129198Scognet u_int32_t l; 76129198Scognet}; 77129198Scognetunion q_util { 78129198Scognet u_int16_t s[4]; 79129198Scognet u_int32_t l[2]; 80129198Scognet u_int64_t q; 81129198Scognet}; 82129198Scognet 83129198Scognetu_short 84129198Scognetin_addword(u_short a, u_short b) 85129198Scognet{ 86129198Scognet u_int64_t sum = a + b; 87129198Scognet 88129198Scognet ADDCARRY(sum); 89129198Scognet return (sum); 90129198Scognet} 91129198Scognet 92160459Scognetstatic 93160459Scognetuint64_t _do_cksum(void *addr, int len) 94160459Scognet{ 95160459Scognet uint64_t sum; 96160459Scognet union q_util q_util; 97160459Scognet 98160459Scognet sum = do_cksum(addr, len); 99160459Scognet REDUCE32; 100160459Scognet return (sum); 101160459Scognet} 102160459Scognet 103129198Scognetu_short 104129198Scognetin_cksum_skip(struct mbuf *m, int len, int skip) 105129198Scognet{ 106129198Scognet u_int64_t sum = 0; 107129198Scognet int mlen = 0; 108129198Scognet int clen = 0; 109129198Scognet caddr_t addr; 110129198Scognet union q_util q_util; 111129198Scognet union l_util l_util; 112129198Scognet 113129198Scognet len -= skip; 114129198Scognet for (; skip && m; m = m->m_next) { 115129198Scognet if (m->m_len > skip) { 116129198Scognet mlen = m->m_len - skip; 117129198Scognet addr = mtod(m, caddr_t) + skip; 118129198Scognet goto skip_start; 119129198Scognet } else { 120129198Scognet skip -= m->m_len; 121129198Scognet } 122129198Scognet } 123129198Scognet 124129198Scognet for (; m && len; m = m->m_next) { 125129198Scognet if (m->m_len == 0) 126129198Scognet continue; 127129198Scognet mlen = m->m_len; 128129198Scognet addr = mtod(m, caddr_t); 129129198Scognetskip_start: 130129198Scognet if (len < mlen) 131129198Scognet mlen = len; 132129198Scognet 133129198Scognet if ((clen ^ (int) addr) & 1) 134160459Scognet sum += _do_cksum(addr, mlen) << 8; 135129198Scognet else 136160459Scognet sum += _do_cksum(addr, mlen); 137129198Scognet 138129198Scognet clen += mlen; 139129198Scognet len -= mlen; 140129198Scognet } 141129198Scognet REDUCE16; 142129198Scognet return (~sum & 0xffff); 143129198Scognet} 144156520Scognet 145156520Scognetu_int in_cksum_hdr(const struct ip *ip) 146156520Scognet{ 147156520Scognet u_int64_t sum = do_cksum(ip, sizeof(struct ip)); 148156520Scognet union q_util q_util; 149156520Scognet union l_util l_util; 150156520Scognet REDUCE16; 151156520Scognet return (~sum & 0xffff); 152236991Simp} 153