xref: /csrg-svn/sys/netns/ns_cksum.c (revision 44529)
125949Ssam /*
233597Ssklower  * Copyright (c) 1982, 1988 Regents of the University of California.
333597Ssklower  * All rights reserved.
433597Ssklower  *
5*44529Sbostic  * %sccs.include.redist.c%
633597Ssklower  *
7*44529Sbostic  *	@(#)ns_cksum.c	7.5 (Berkeley) 06/28/90
825949Ssam  */
934863Sbostic 
1038987Ssklower #include "param.h"
1125949Ssam #include "mbuf.h"
1225949Ssam /*
1333634Ssklower  * Checksum routine for Network Systems Protocol Packets (Big-Endian).
1425949Ssam  *
1533597Ssklower  * This routine is very heavily used in the network
1633597Ssklower  * code and should be modified for each CPU to be as fast as possible.
1725949Ssam  */
1833597Ssklower 
1934496Skarels #define ADDCARRY(x)  { if ((x) > 65535) (x) -= 65535; }
2034496Skarels #define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);}
2133597Ssklower 
2225949Ssam u_short
2325949Ssam ns_cksum(m, len)
2425949Ssam 	register struct mbuf *m;
2525949Ssam 	register int len;
2625949Ssam {
2733597Ssklower 	register u_short *w;
2833597Ssklower 	register int sum = 0;
2933597Ssklower 	register int mlen = 0;
3033597Ssklower 	register int sum2;
3125949Ssam 
3233597Ssklower 	union {
3333597Ssklower 		u_short s[2];
3433597Ssklower 		long	l;
3533597Ssklower 	} l_util;
3633597Ssklower 
3733597Ssklower 	for (;m && len; m = m->m_next) {
3833597Ssklower 		if (m->m_len == 0)
3933597Ssklower 			continue;
4033597Ssklower 		/*
4133597Ssklower 		 * Each trip around loop adds in
4233597Ssklower 		 * word from one mbuf segment.
4333597Ssklower 		 */
4433597Ssklower 		w = mtod(m, u_short *);
4533597Ssklower 		if (mlen == -1) {
4633597Ssklower 			/*
4733597Ssklower 			 * There is a byte left from the last segment;
4833597Ssklower 			 * ones-complement add it into the checksum.
4933597Ssklower 			 */
5033597Ssklower 			sum  += *(u_char *)w; /* Big-Endian, else << 8 */
5133597Ssklower 			sum += sum;
5233597Ssklower 			w = (u_short *)(1 + (char *)w);
5333597Ssklower 			mlen = m->m_len - 1;
5433597Ssklower 			len--;
5533597Ssklower 			FOLD(sum);
5633597Ssklower 		} else
5733597Ssklower 			mlen = m->m_len;
5833597Ssklower 		if (len < mlen)
5933597Ssklower 			mlen = len;
6033597Ssklower 		len -= mlen;
6133597Ssklower 		/*
6233597Ssklower 		 * We can do a 16 bit ones complement sum using
6333597Ssklower 		 * 32 bit arithmetic registers for adding,
6433597Ssklower 		 * with carries from the low added
6533597Ssklower 		 * into the high (by normal carry-chaining)
6633597Ssklower 		 * so long as we fold back before 16 carries have occured.
6733597Ssklower 		 */
6833597Ssklower 		if (1 & (int) w)
6933597Ssklower 			goto uuuuglyy;
7033597Ssklower #ifndef TINY
7133597Ssklower /* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */
7233597Ssklower 		while ((mlen -= 32) >= 0) {
7333597Ssklower 			sum += w[0]; sum += sum; sum += w[1]; sum += sum;
7433597Ssklower 			sum += w[2]; sum += sum; sum += w[3]; sum += sum;
7533597Ssklower 			sum += w[4]; sum += sum; sum += w[5]; sum += sum;
7633597Ssklower 			sum += w[6]; sum += sum; sum += w[7]; sum += sum;
7733597Ssklower 			FOLD(sum);
7833597Ssklower 			sum += w[8]; sum += sum; sum += w[9]; sum += sum;
7933597Ssklower 			sum += w[10]; sum += sum; sum += w[11]; sum += sum;
8033597Ssklower 			sum += w[12]; sum += sum; sum += w[13]; sum += sum;
8133597Ssklower 			sum += w[14]; sum += sum; sum += w[15]; sum += sum;
8233597Ssklower 			FOLD(sum);
8333597Ssklower 			w += 16;
8425949Ssam 		}
8533597Ssklower 		mlen += 32;
8633597Ssklower #endif
8733597Ssklower 		while ((mlen -= 8) >= 0) {
8833597Ssklower 			sum += w[0]; sum += sum; sum += w[1]; sum += sum;
8933597Ssklower 			sum += w[2]; sum += sum; sum += w[3]; sum += sum;
9033597Ssklower 			FOLD(sum);
9133597Ssklower 			w += 4;
9233597Ssklower 		}
9333597Ssklower 		mlen += 8;
9433597Ssklower 		while ((mlen -= 2) >= 0) {
9533597Ssklower 			sum += *w++; sum += sum;
9633597Ssklower 		}
9733597Ssklower 		goto commoncase;
9833597Ssklower uuuuglyy:
9933597Ssklower /* Big-Endian; else reverse ww and vv */
10033634Ssklower #define ww(n) (((u_char *)w)[n + n + 1])
10133634Ssklower #define vv(n) (((u_char *)w)[n + n])
10233597Ssklower 		sum2 = 0;
10333597Ssklower #ifndef TINY
10433597Ssklower 		while ((mlen -= 32) >= 0) {
10533597Ssklower 		    sum += ww(0); sum += sum; sum += ww(1); sum += sum;
10633597Ssklower 		    sum += ww(2); sum += sum; sum += ww(3); sum += sum;
10733597Ssklower 		    sum += ww(4); sum += sum; sum += ww(5); sum += sum;
10833597Ssklower 		    sum += ww(6); sum += sum; sum += ww(7); sum += sum;
10933597Ssklower 		    FOLD(sum);
11033597Ssklower 		    sum += ww(8); sum += sum; sum += ww(9); sum += sum;
11133597Ssklower 		    sum += ww(10); sum += sum; sum += ww(11); sum += sum;
11233597Ssklower 		    sum += ww(12); sum += sum; sum += ww(13); sum += sum;
11333597Ssklower 		    sum += ww(14); sum += sum; sum += ww(15); sum += sum;
11433597Ssklower 		    FOLD(sum);
11533597Ssklower 		    sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2;
11633597Ssklower 		    sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2;
11733597Ssklower 		    sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2;
11833597Ssklower 		    sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2;
11933597Ssklower 		    FOLD(sum2);
12033597Ssklower 		    sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2;
12133597Ssklower 		    sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2;
12233597Ssklower 		    sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2;
12333597Ssklower 		    sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2;
12433597Ssklower 		    FOLD(sum2);
12533597Ssklower 		    w += 16;
12633597Ssklower 		}
12733597Ssklower 		mlen += 32;
12833597Ssklower #endif
12933597Ssklower 		while ((mlen -= 8) >= 0) {
13033597Ssklower 		    sum += ww(0); sum += sum; sum += ww(1); sum += sum;
13133597Ssklower 		    sum += ww(2); sum += sum; sum += ww(3); sum += sum;
13233597Ssklower 		    FOLD(sum);
13333597Ssklower 		    sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2;
13433597Ssklower 		    sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2;
13533597Ssklower 		    FOLD(sum2);
13633597Ssklower 		    w += 4;
13733597Ssklower 		}
13833597Ssklower 		mlen += 8;
13933597Ssklower 		while ((mlen -= 2) >= 0) {
14033597Ssklower 			sum += ww(0); sum += sum;
14133597Ssklower 			sum2 += vv(0); sum2 += sum2;
14233597Ssklower 			w++;
14333597Ssklower 		}
14433597Ssklower 		sum += (sum2 << 8);
14533597Ssklower commoncase:
14633597Ssklower 		if (mlen == -1) {
14733597Ssklower 			sum += *(u_char *)w << 8; /* Big-Endian, else no << 8 */
14833597Ssklower 		}
14933597Ssklower 		FOLD(sum);
15025949Ssam 	}
15133597Ssklower 	if (mlen == -1) {
15233597Ssklower 		/* We had an odd number of bytes to sum; assume a garbage
15333597Ssklower 		   byte of zero and clean up */
15433597Ssklower 		sum += sum;
15533597Ssklower 		FOLD(sum);
15633597Ssklower 	}
15733597Ssklower 	/*
15833597Ssklower 	 * sum has already been kept to low sixteen bits.
15933597Ssklower 	 * just examine result and exit.
16033597Ssklower 	 */
16133597Ssklower 	if(sum==0xffff) sum = 0;
16233597Ssklower 	return (sum);
16325949Ssam }
164