xref: /csrg-svn/sys/netinet/in_cksum.c (revision 56531)
133840Skarels /*
252796Ssklower  * Copyright (c) 1988, 1992 Regents of the University of California.
333840Skarels  * All rights reserved.
433840Skarels  *
544474Sbostic  * %sccs.include.redist.c%
633840Skarels  *
7*56531Sbostic  *	@(#)in_cksum.c	7.5 (Berkeley) 10/11/92
833840Skarels  */
933840Skarels 
10*56531Sbostic #include <sys/param.h>
11*56531Sbostic #include <sys/mbuf.h>
1233840Skarels 
1333840Skarels /*
1433840Skarels  * Checksum routine for Internet Protocol family headers (Portable Version).
1533840Skarels  *
1633840Skarels  * This routine is very heavily used in the network
1733840Skarels  * code and should be modified for each CPU to be as fast as possible.
1833840Skarels  */
1933840Skarels 
2033840Skarels #define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
2133840Skarels #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
2233840Skarels 
2352796Ssklower in_cksum(m, len)
2433840Skarels 	register struct mbuf *m;
2533840Skarels 	register int len;
2633840Skarels {
2733840Skarels 	register u_short *w;
2833840Skarels 	register int sum = 0;
2933840Skarels 	register int mlen = 0;
3033840Skarels 	int byte_swapped = 0;
3133840Skarels 
3233840Skarels 	union {
3333840Skarels 		char	c[2];
3433840Skarels 		u_short	s;
3533840Skarels 	} s_util;
3633840Skarels 	union {
3733840Skarels 		u_short s[2];
3833840Skarels 		long	l;
3933840Skarels 	} l_util;
4033840Skarels 
4133840Skarels 	for (;m && len; m = m->m_next) {
4233840Skarels 		if (m->m_len == 0)
4333840Skarels 			continue;
4433840Skarels 		w = mtod(m, u_short *);
4533840Skarels 		if (mlen == -1) {
4633840Skarels 			/*
4733840Skarels 			 * The first byte of this mbuf is the continuation
4833840Skarels 			 * of a word spanning between this mbuf and the
4933840Skarels 			 * last mbuf.
5033840Skarels 			 *
5133840Skarels 			 * s_util.c[0] is already saved when scanning previous
5233840Skarels 			 * mbuf.
5333840Skarels 			 */
5433840Skarels 			s_util.c[1] = *(char *)w;
5533840Skarels 			sum += s_util.s;
5633840Skarels 			w = (u_short *)((char *)w + 1);
5733840Skarels 			mlen = m->m_len - 1;
5833840Skarels 			len--;
5933840Skarels 		} else
6033840Skarels 			mlen = m->m_len;
6133840Skarels 		if (len < mlen)
6233840Skarels 			mlen = len;
6333840Skarels 		len -= mlen;
6433840Skarels 		/*
6533840Skarels 		 * Force to even boundary.
6633840Skarels 		 */
6733840Skarels 		if ((1 & (int) w) && (mlen > 0)) {
6833840Skarels 			REDUCE;
6933840Skarels 			sum <<= 8;
7033840Skarels 			s_util.c[0] = *(u_char *)w;
7133840Skarels 			w = (u_short *)((char *)w + 1);
7233840Skarels 			mlen--;
7333840Skarels 			byte_swapped = 1;
7433840Skarels 		}
7533840Skarels 		/*
7633840Skarels 		 * Unroll the loop to make overhead from
7733840Skarels 		 * branches &c small.
7833840Skarels 		 */
7933840Skarels 		while ((mlen -= 32) >= 0) {
8033840Skarels 			sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
8133840Skarels 			sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
8233840Skarels 			sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
8333840Skarels 			sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
8433840Skarels 			w += 16;
8533840Skarels 		}
8633840Skarels 		mlen += 32;
8733840Skarels 		while ((mlen -= 8) >= 0) {
8833840Skarels 			sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
8933840Skarels 			w += 4;
9033840Skarels 		}
9133840Skarels 		mlen += 8;
9233840Skarels 		if (mlen == 0 && byte_swapped == 0)
9333840Skarels 			continue;
9433840Skarels 		REDUCE;
9533840Skarels 		while ((mlen -= 2) >= 0) {
9633840Skarels 			sum += *w++;
9733840Skarels 		}
9833840Skarels 		if (byte_swapped) {
9933840Skarels 			REDUCE;
10033840Skarels 			sum <<= 8;
10133840Skarels 			byte_swapped = 0;
10233840Skarels 			if (mlen == -1) {
10333840Skarels 				s_util.c[1] = *(char *)w;
10433840Skarels 				sum += s_util.s;
10533840Skarels 				mlen = 0;
10633840Skarels 			} else
10733840Skarels 				mlen = -1;
10833840Skarels 		} else if (mlen == -1)
10933840Skarels 			s_util.c[0] = *(char *)w;
11033840Skarels 	}
11133840Skarels 	if (len)
11233840Skarels 		printf("cksum: out of data\n");
11333840Skarels 	if (mlen == -1) {
11433840Skarels 		/* The last mbuf has odd # of bytes. Follow the
11533840Skarels 		   standard (the odd byte may be shifted left by 8 bits
11633840Skarels 		   or not as determined by endian-ness of the machine) */
11733840Skarels 		s_util.c[1] = 0;
11833840Skarels 		sum += s_util.s;
11933840Skarels 	}
12033840Skarels 	REDUCE;
12133840Skarels 	return (~sum & 0xffff);
12233840Skarels }
123