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