xref: /csrg-svn/sys/netns/ns_cksum.c (revision 63231)
125949Ssam /*
2*63231Sbostic  * Copyright (c) 1982, 1992, 1993
3*63231Sbostic  *	The Regents of the University of California.  All rights reserved.
433597Ssklower  *
544529Sbostic  * %sccs.include.redist.c%
633597Ssklower  *
7*63231Sbostic  *	@(#)ns_cksum.c	8.1 (Berkeley) 06/10/93
825949Ssam  */
934863Sbostic 
1056534Sbostic #include <sys/param.h>
1156534Sbostic #include <sys/mbuf.h>
1245798Sbostic 
1325949Ssam /*
1433634Ssklower  * Checksum routine for Network Systems Protocol Packets (Big-Endian).
1525949Ssam  *
1633597Ssklower  * This routine is very heavily used in the network
1733597Ssklower  * code and should be modified for each CPU to be as fast as possible.
1825949Ssam  */
1933597Ssklower 
2034496Skarels #define ADDCARRY(x)  { if ((x) > 65535) (x) -= 65535; }
2134496Skarels #define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);}
2233597Ssklower 
2325949Ssam u_short
ns_cksum(m,len)2425949Ssam ns_cksum(m, len)
2525949Ssam 	register struct mbuf *m;
2625949Ssam 	register int len;
2725949Ssam {
2833597Ssklower 	register u_short *w;
2933597Ssklower 	register int sum = 0;
3033597Ssklower 	register int mlen = 0;
3133597Ssklower 	register int sum2;
3225949Ssam 
3333597Ssklower 	union {
3433597Ssklower 		u_short s[2];
3533597Ssklower 		long	l;
3633597Ssklower 	} l_util;
3733597Ssklower 
3833597Ssklower 	for (;m && len; m = m->m_next) {
3933597Ssklower 		if (m->m_len == 0)
4033597Ssklower 			continue;
4133597Ssklower 		/*
4233597Ssklower 		 * Each trip around loop adds in
4333597Ssklower 		 * word from one mbuf segment.
4433597Ssklower 		 */
4533597Ssklower 		w = mtod(m, u_short *);
4633597Ssklower 		if (mlen == -1) {
4733597Ssklower 			/*
4833597Ssklower 			 * There is a byte left from the last segment;
4933597Ssklower 			 * ones-complement add it into the checksum.
5033597Ssklower 			 */
5148841Ssklower #if BYTE_ORDER == BIG_ENDIAN
5248841Ssklower 			sum  += *(u_char *)w;
5348841Ssklower #else
5448841Ssklower 			sum  += *(u_char *)w << 8;
5548841Ssklower #endif
5633597Ssklower 			sum += sum;
5733597Ssklower 			w = (u_short *)(1 + (char *)w);
5833597Ssklower 			mlen = m->m_len - 1;
5933597Ssklower 			len--;
6033597Ssklower 			FOLD(sum);
6133597Ssklower 		} else
6233597Ssklower 			mlen = m->m_len;
6333597Ssklower 		if (len < mlen)
6433597Ssklower 			mlen = len;
6533597Ssklower 		len -= mlen;
6633597Ssklower 		/*
6733597Ssklower 		 * We can do a 16 bit ones complement sum using
6833597Ssklower 		 * 32 bit arithmetic registers for adding,
6933597Ssklower 		 * with carries from the low added
7033597Ssklower 		 * into the high (by normal carry-chaining)
7133597Ssklower 		 * so long as we fold back before 16 carries have occured.
7233597Ssklower 		 */
7333597Ssklower 		if (1 & (int) w)
7433597Ssklower 			goto uuuuglyy;
7533597Ssklower #ifndef TINY
7633597Ssklower /* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */
7733597Ssklower 		while ((mlen -= 32) >= 0) {
7833597Ssklower 			sum += w[0]; sum += sum; sum += w[1]; sum += sum;
7933597Ssklower 			sum += w[2]; sum += sum; sum += w[3]; sum += sum;
8033597Ssklower 			sum += w[4]; sum += sum; sum += w[5]; sum += sum;
8133597Ssklower 			sum += w[6]; sum += sum; sum += w[7]; sum += sum;
8233597Ssklower 			FOLD(sum);
8333597Ssklower 			sum += w[8]; sum += sum; sum += w[9]; sum += sum;
8433597Ssklower 			sum += w[10]; sum += sum; sum += w[11]; sum += sum;
8533597Ssklower 			sum += w[12]; sum += sum; sum += w[13]; sum += sum;
8633597Ssklower 			sum += w[14]; sum += sum; sum += w[15]; sum += sum;
8733597Ssklower 			FOLD(sum);
8833597Ssklower 			w += 16;
8925949Ssam 		}
9033597Ssklower 		mlen += 32;
9133597Ssklower #endif
9233597Ssklower 		while ((mlen -= 8) >= 0) {
9333597Ssklower 			sum += w[0]; sum += sum; sum += w[1]; sum += sum;
9433597Ssklower 			sum += w[2]; sum += sum; sum += w[3]; sum += sum;
9533597Ssklower 			FOLD(sum);
9633597Ssklower 			w += 4;
9733597Ssklower 		}
9833597Ssklower 		mlen += 8;
9933597Ssklower 		while ((mlen -= 2) >= 0) {
10033597Ssklower 			sum += *w++; sum += sum;
10133597Ssklower 		}
10233597Ssklower 		goto commoncase;
10333597Ssklower uuuuglyy:
10448841Ssklower #if BYTE_ORDER == BIG_ENDIAN
10533634Ssklower #define ww(n) (((u_char *)w)[n + n + 1])
10633634Ssklower #define vv(n) (((u_char *)w)[n + n])
10748841Ssklower #else
10848841Ssklower #if BYTE_ORDER == LITTLE_ENDIAN
10948841Ssklower #define vv(n) (((u_char *)w)[n + n + 1])
11048841Ssklower #define ww(n) (((u_char *)w)[n + n])
11148841Ssklower #endif
11248841Ssklower #endif
11333597Ssklower 		sum2 = 0;
11433597Ssklower #ifndef TINY
11533597Ssklower 		while ((mlen -= 32) >= 0) {
11633597Ssklower 		    sum += ww(0); sum += sum; sum += ww(1); sum += sum;
11733597Ssklower 		    sum += ww(2); sum += sum; sum += ww(3); sum += sum;
11833597Ssklower 		    sum += ww(4); sum += sum; sum += ww(5); sum += sum;
11933597Ssklower 		    sum += ww(6); sum += sum; sum += ww(7); sum += sum;
12033597Ssklower 		    FOLD(sum);
12133597Ssklower 		    sum += ww(8); sum += sum; sum += ww(9); sum += sum;
12233597Ssklower 		    sum += ww(10); sum += sum; sum += ww(11); sum += sum;
12333597Ssklower 		    sum += ww(12); sum += sum; sum += ww(13); sum += sum;
12433597Ssklower 		    sum += ww(14); sum += sum; sum += ww(15); sum += sum;
12533597Ssklower 		    FOLD(sum);
12633597Ssklower 		    sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2;
12733597Ssklower 		    sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2;
12833597Ssklower 		    sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2;
12933597Ssklower 		    sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2;
13033597Ssklower 		    FOLD(sum2);
13133597Ssklower 		    sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2;
13233597Ssklower 		    sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2;
13333597Ssklower 		    sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2;
13433597Ssklower 		    sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2;
13533597Ssklower 		    FOLD(sum2);
13633597Ssklower 		    w += 16;
13733597Ssklower 		}
13833597Ssklower 		mlen += 32;
13933597Ssklower #endif
14033597Ssklower 		while ((mlen -= 8) >= 0) {
14133597Ssklower 		    sum += ww(0); sum += sum; sum += ww(1); sum += sum;
14233597Ssklower 		    sum += ww(2); sum += sum; sum += ww(3); sum += sum;
14333597Ssklower 		    FOLD(sum);
14433597Ssklower 		    sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2;
14533597Ssklower 		    sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2;
14633597Ssklower 		    FOLD(sum2);
14733597Ssklower 		    w += 4;
14833597Ssklower 		}
14933597Ssklower 		mlen += 8;
15033597Ssklower 		while ((mlen -= 2) >= 0) {
15133597Ssklower 			sum += ww(0); sum += sum;
15233597Ssklower 			sum2 += vv(0); sum2 += sum2;
15333597Ssklower 			w++;
15433597Ssklower 		}
15533597Ssklower 		sum += (sum2 << 8);
15633597Ssklower commoncase:
15733597Ssklower 		if (mlen == -1) {
15848841Ssklower #if BYTE_ORDER == BIG_ENDIAN
15948841Ssklower 			sum += *(u_char *)w << 8;
16048841Ssklower #else
16148841Ssklower 			sum += *(u_char *)w;
16248841Ssklower #endif
16333597Ssklower 		}
16433597Ssklower 		FOLD(sum);
16525949Ssam 	}
16633597Ssklower 	if (mlen == -1) {
16733597Ssklower 		/* We had an odd number of bytes to sum; assume a garbage
16833597Ssklower 		   byte of zero and clean up */
16933597Ssklower 		sum += sum;
17033597Ssklower 		FOLD(sum);
17133597Ssklower 	}
17233597Ssklower 	/*
17333597Ssklower 	 * sum has already been kept to low sixteen bits.
17433597Ssklower 	 * just examine result and exit.
17533597Ssklower 	 */
17633597Ssklower 	if(sum==0xffff) sum = 0;
17733597Ssklower 	return (sum);
17825949Ssam }
179