in_cksum.c revision 620
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	from tahoe:	in_cksum.c	1.2	86/01/05
34 *	from:		@(#)in_cksum.c	1.3 (Berkeley) 1/19/91
35 *	$Id$
36 */
37
38#include "param.h"
39#include "sys/mbuf.h"
40
41/*
42 * Checksum routine for Internet Protocol family headers.
43 *
44 * This routine is very heavily used in the network
45 * code and should be modified for each CPU to be as fast as possible.
46 *
47 * This implementation is 386 version.
48 */
49
50#undef	ADDCARRY
51#define ADDCARRY(x)     if ((x) > 0xffff) (x) -= 0xffff
52#define REDUCE          {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);}
53
54/*
55 * Thanks to gcc we don't have to guess
56 * which registers contain sum & w.
57 */
58#define CLC     asm("clc")
59#define ADD(n)  asm("adcl " #n "(%2), %0": "=r"(sum): "0"(sum), "r"(w))
60#define MOP     asm("adcl $0, %0":         "=r"(sum): "0"(sum))
61
62in_cksum(m, len)
63	register struct mbuf *m;
64	register int len;
65{
66	register u_short *w;
67	register unsigned sum = 0;
68	register int mlen = 0;
69	int byte_swapped = 0;
70	union { char	c[2]; u_short	s; } su;
71
72	for (;m && len; m = m->m_next) {
73		if (m->m_len == 0)
74			continue;
75		w = mtod(m, u_short *);
76		if (mlen == -1) {
77			/*
78			 * The first byte of this mbuf is the continuation
79			 * of a word spanning between this mbuf and the
80			 * last mbuf.
81			 */
82
83			/* su.c[0] is already saved when scanning previous
84			 * mbuf.  sum was REDUCEd when we found mlen == -1
85			 */
86			su.c[1] = *(u_char *)w;
87			sum += su.s;
88			w = (u_short *)((char *)w + 1);
89			mlen = m->m_len - 1;
90			len--;
91		} else
92			mlen = m->m_len;
93		if (len < mlen)
94			mlen = len;
95		len -= mlen;
96		/*
97		 * Force to long boundary so we do longword aligned
98		 * memory operations
99		 */
100		if (3 & (int) w) {
101			REDUCE;
102			if ((1 & (int) w) && (mlen > 0)) {
103				sum <<= 8;
104				su.c[0] = *(char *)w;
105				w = (u_short *)((char *)w + 1);
106				mlen--;
107				byte_swapped = 1;
108			}
109			if ((2 & (int) w) && (mlen >= 2)) {
110				sum += *w++;
111				mlen -= 2;
112			}
113		}
114		/*
115		 * Do as much of the checksum as possible 32 bits at at time.
116		 * In fact, this loop is unrolled to make overhead from
117		 * branches &c small.
118		 */
119		while ((mlen -= 32) >= 0) {
120			/*
121			 * Clear the carry flag, add with carry 16 words
122			 * and fold-in last carry by adding a 0 with carry.
123			 */
124			CLC;
125			ADD(0);  ADD(4);  ADD(8);  ADD(12);
126			ADD(16); ADD(20); ADD(24); ADD(28);
127			MOP; w += 16;
128		}
129		mlen += 32;
130		while ((mlen -= 8) >= 0) {
131			CLC;
132			ADD(0); ADD(4);
133			MOP;
134			w += 4;
135		}
136		mlen += 8;
137		if (mlen == 0 && byte_swapped == 0)
138			continue;       /* worth 1% maybe ?? */
139		REDUCE;
140		while ((mlen -= 2) >= 0) {
141			sum += *w++;
142		}
143		if (byte_swapped) {
144			sum <<= 8;
145			byte_swapped = 0;
146			if (mlen == -1) {
147				su.c[1] = *(char *)w;
148				sum += su.s;
149				mlen = 0;
150			} else
151				mlen = -1;
152		} else if (mlen == -1)
153			/*
154			 * This mbuf has odd number of bytes.
155			 * There could be a word split betwen
156			 * this mbuf and the next mbuf.
157			 * Save the last byte (to prepend to next mbuf).
158			 */
159			su.c[0] = *(char *)w;
160	}
161
162	if (len)
163		printf("cksum: out of data\n");
164	if (mlen == -1) {
165		/* The last mbuf has odd # of bytes. Follow the
166		   standard (the odd byte is shifted left by 8 bits) */
167		su.c[1] = 0;
168		sum += su.s;
169	}
170	REDUCE;
171	return (~sum & 0xffff);
172}
173
174