ipx_cksum.c revision 11991
111819Sjulian/*
211819Sjulian * Copyright (c) 1995, Mike Mitchell
311819Sjulian * Copyright (c) 1982, 1992, 1993
411819Sjulian *	The Regents of the University of California.  All rights reserved.
511819Sjulian *
611819Sjulian * Redistribution and use in source and binary forms, with or without
711819Sjulian * modification, are permitted provided that the following conditions
811819Sjulian * are met:
911819Sjulian * 1. Redistributions of source code must retain the above copyright
1011819Sjulian *    notice, this list of conditions and the following disclaimer.
1111819Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1211819Sjulian *    notice, this list of conditions and the following disclaimer in the
1311819Sjulian *    documentation and/or other materials provided with the distribution.
1411819Sjulian * 3. All advertising materials mentioning features or use of this software
1511819Sjulian *    must display the following acknowledgement:
1611819Sjulian *	This product includes software developed by the University of
1711819Sjulian *	California, Berkeley and its contributors.
1811819Sjulian * 4. Neither the name of the University nor the names of its contributors
1911819Sjulian *    may be used to endorse or promote products derived from this software
2011819Sjulian *    without specific prior written permission.
2111819Sjulian *
2211819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2311819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2411819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2511819Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2611819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2711819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2811819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2911819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3011819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3111819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3211819Sjulian * SUCH DAMAGE.
3311819Sjulian *
3411991Sjulian *	@(#)$Id$
3511819Sjulian */
3611819Sjulian
3711819Sjulian#include <sys/param.h>
3811819Sjulian#include <sys/mbuf.h>
3911819Sjulian
4011991Sjulian#include <netipx/ipx.h>
4111991Sjulian
4211819Sjulian/*
4311819Sjulian * Checksum routine for Network Systems Protocol Packets (Big-Endian).
4411819Sjulian *
4511819Sjulian * This routine is very heavily used in the network
4611819Sjulian * code and should be modified for each CPU to be as fast as possible.
4711819Sjulian */
4811819Sjulian
4911819Sjulian#define ADDCARRY(x)  { if ((x) > 65535) (x) -= 65535; }
5011819Sjulian#define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);}
5111819Sjulian
5211819Sjulianu_short
5311819Sjulianipx_cksum(m, len)
5411991Sjulian	struct mbuf *m;
5511991Sjulian	int len;
5611819Sjulian{
5711819Sjulian	register u_short *w;
5811819Sjulian	register int sum = 0;
5911819Sjulian	register int mlen = 0;
6011819Sjulian	register int sum2;
6111819Sjulian
6211819Sjulian	union {
6311819Sjulian		u_short s[2];
6411819Sjulian		long	l;
6511819Sjulian	} l_util;
6611819Sjulian
6711819Sjulian	for (;m && len; m = m->m_next) {
6811819Sjulian		if (m->m_len == 0)
6911819Sjulian			continue;
7011819Sjulian		/*
7111819Sjulian		 * Each trip around loop adds in
7211819Sjulian		 * word from one mbuf segment.
7311819Sjulian		 */
7411819Sjulian		w = mtod(m, u_short *);
7511819Sjulian		if (mlen == -1) {
7611819Sjulian			/*
7711819Sjulian			 * There is a byte left from the last segment;
7811819Sjulian			 * ones-complement add it into the checksum.
7911819Sjulian			 */
8011819Sjulian#if BYTE_ORDER == BIG_ENDIAN
8111819Sjulian			sum  += *(u_char *)w;
8211819Sjulian#else
8311819Sjulian			sum  += *(u_char *)w << 8;
8411819Sjulian#endif
8511819Sjulian			sum += sum;
8611819Sjulian			w = (u_short *)(1 + (char *)w);
8711819Sjulian			mlen = m->m_len - 1;
8811819Sjulian			len--;
8911819Sjulian			FOLD(sum);
9011819Sjulian		} else
9111819Sjulian			mlen = m->m_len;
9211819Sjulian		if (len < mlen)
9311819Sjulian			mlen = len;
9411819Sjulian		len -= mlen;
9511819Sjulian		/*
9611819Sjulian		 * We can do a 16 bit ones complement sum using
9711819Sjulian		 * 32 bit arithmetic registers for adding,
9811819Sjulian		 * with carries from the low added
9911819Sjulian		 * into the high (by normal carry-chaining)
10011819Sjulian		 * so long as we fold back before 16 carries have occured.
10111819Sjulian		 */
10211819Sjulian		if (1 & (int) w)
10311819Sjulian			goto uuuuglyy;
10411819Sjulian#ifndef TINY
10511819Sjulian/* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */
10611819Sjulian		while ((mlen -= 32) >= 0) {
10711819Sjulian			sum += w[0]; sum += sum; sum += w[1]; sum += sum;
10811819Sjulian			sum += w[2]; sum += sum; sum += w[3]; sum += sum;
10911819Sjulian			sum += w[4]; sum += sum; sum += w[5]; sum += sum;
11011819Sjulian			sum += w[6]; sum += sum; sum += w[7]; sum += sum;
11111819Sjulian			FOLD(sum);
11211819Sjulian			sum += w[8]; sum += sum; sum += w[9]; sum += sum;
11311819Sjulian			sum += w[10]; sum += sum; sum += w[11]; sum += sum;
11411819Sjulian			sum += w[12]; sum += sum; sum += w[13]; sum += sum;
11511819Sjulian			sum += w[14]; sum += sum; sum += w[15]; sum += sum;
11611819Sjulian			FOLD(sum);
11711819Sjulian			w += 16;
11811819Sjulian		}
11911819Sjulian		mlen += 32;
12011819Sjulian#endif
12111819Sjulian		while ((mlen -= 8) >= 0) {
12211819Sjulian			sum += w[0]; sum += sum; sum += w[1]; sum += sum;
12311819Sjulian			sum += w[2]; sum += sum; sum += w[3]; sum += sum;
12411819Sjulian			FOLD(sum);
12511819Sjulian			w += 4;
12611819Sjulian		}
12711819Sjulian		mlen += 8;
12811819Sjulian		while ((mlen -= 2) >= 0) {
12911819Sjulian			sum += *w++; sum += sum;
13011819Sjulian		}
13111819Sjulian		goto commoncase;
13211819Sjulianuuuuglyy:
13311819Sjulian#if BYTE_ORDER == BIG_ENDIAN
13411819Sjulian#define ww(n) (((u_char *)w)[n + n + 1])
13511819Sjulian#define vv(n) (((u_char *)w)[n + n])
13611819Sjulian#else
13711819Sjulian#if BYTE_ORDER == LITTLE_ENDIAN
13811819Sjulian#define vv(n) (((u_char *)w)[n + n + 1])
13911819Sjulian#define ww(n) (((u_char *)w)[n + n])
14011819Sjulian#endif
14111819Sjulian#endif
14211819Sjulian		sum2 = 0;
14311819Sjulian#ifndef TINY
14411819Sjulian		while ((mlen -= 32) >= 0) {
14511819Sjulian		    sum += ww(0); sum += sum; sum += ww(1); sum += sum;
14611819Sjulian		    sum += ww(2); sum += sum; sum += ww(3); sum += sum;
14711819Sjulian		    sum += ww(4); sum += sum; sum += ww(5); sum += sum;
14811819Sjulian		    sum += ww(6); sum += sum; sum += ww(7); sum += sum;
14911819Sjulian		    FOLD(sum);
15011819Sjulian		    sum += ww(8); sum += sum; sum += ww(9); sum += sum;
15111819Sjulian		    sum += ww(10); sum += sum; sum += ww(11); sum += sum;
15211819Sjulian		    sum += ww(12); sum += sum; sum += ww(13); sum += sum;
15311819Sjulian		    sum += ww(14); sum += sum; sum += ww(15); sum += sum;
15411819Sjulian		    FOLD(sum);
15511819Sjulian		    sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2;
15611819Sjulian		    sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2;
15711819Sjulian		    sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2;
15811819Sjulian		    sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2;
15911819Sjulian		    FOLD(sum2);
16011819Sjulian		    sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2;
16111819Sjulian		    sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2;
16211819Sjulian		    sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2;
16311819Sjulian		    sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2;
16411819Sjulian		    FOLD(sum2);
16511819Sjulian		    w += 16;
16611819Sjulian		}
16711819Sjulian		mlen += 32;
16811819Sjulian#endif
16911819Sjulian		while ((mlen -= 8) >= 0) {
17011819Sjulian		    sum += ww(0); sum += sum; sum += ww(1); sum += sum;
17111819Sjulian		    sum += ww(2); sum += sum; sum += ww(3); sum += sum;
17211819Sjulian		    FOLD(sum);
17311819Sjulian		    sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2;
17411819Sjulian		    sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2;
17511819Sjulian		    FOLD(sum2);
17611819Sjulian		    w += 4;
17711819Sjulian		}
17811819Sjulian		mlen += 8;
17911819Sjulian		while ((mlen -= 2) >= 0) {
18011819Sjulian			sum += ww(0); sum += sum;
18111819Sjulian			sum2 += vv(0); sum2 += sum2;
18211819Sjulian			w++;
18311819Sjulian		}
18411819Sjulian		sum += (sum2 << 8);
18511819Sjuliancommoncase:
18611819Sjulian		if (mlen == -1) {
18711819Sjulian#if BYTE_ORDER == BIG_ENDIAN
18811819Sjulian			sum += *(u_char *)w << 8;
18911819Sjulian#else
19011819Sjulian			sum += *(u_char *)w;
19111819Sjulian#endif
19211819Sjulian		}
19311819Sjulian		FOLD(sum);
19411819Sjulian	}
19511819Sjulian	if (mlen == -1) {
19611819Sjulian		/* We had an odd number of bytes to sum; assume a garbage
19711819Sjulian		   byte of zero and clean up */
19811819Sjulian		sum += sum;
19911819Sjulian		FOLD(sum);
20011819Sjulian	}
20111819Sjulian	/*
20211819Sjulian	 * sum has already been kept to low sixteen bits.
20311819Sjulian	 * just examine result and exit.
20411819Sjulian	 */
20511819Sjulian	if(sum==0xffff) sum = 0;
20611819Sjulian	return (sum);
20711819Sjulian}
208