xref: /csrg-svn/sys/netinet/in_cksum.c (revision 33840)
1*33840Skarels /*
2*33840Skarels  * Copyright (c) 1988 Regents of the University of California.
3*33840Skarels  * All rights reserved.
4*33840Skarels  *
5*33840Skarels  * Redistribution and use in source and binary forms are permitted
6*33840Skarels  * provided that this notice is preserved and that due credit is given
7*33840Skarels  * to the University of California at Berkeley. The name of the University
8*33840Skarels  * may not be used to endorse or promote products derived from this
9*33840Skarels  * software without specific prior written permission. This software
10*33840Skarels  * is provided ``as is'' without express or implied warranty.
11*33840Skarels  *
12*33840Skarels  *	@(#)in_cksum.c	7.1 (Berkeley) 03/29/88
13*33840Skarels  */
14*33840Skarels 
15*33840Skarels #include "../h/types.h"
16*33840Skarels #include "../h/mbuf.h"
17*33840Skarels 
18*33840Skarels /*
19*33840Skarels  * Checksum routine for Internet Protocol family headers (Portable Version).
20*33840Skarels  *
21*33840Skarels  * This routine is very heavily used in the network
22*33840Skarels  * code and should be modified for each CPU to be as fast as possible.
23*33840Skarels  */
24*33840Skarels 
25*33840Skarels #define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
26*33840Skarels #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
27*33840Skarels 
28*33840Skarels in_cksum_c(m, len)
29*33840Skarels 	register struct mbuf *m;
30*33840Skarels 	register int len;
31*33840Skarels {
32*33840Skarels 	register u_short *w;
33*33840Skarels 	register int sum = 0;
34*33840Skarels 	register int mlen = 0;
35*33840Skarels 	int byte_swapped = 0;
36*33840Skarels 
37*33840Skarels 	union {
38*33840Skarels 		char	c[2];
39*33840Skarels 		u_short	s;
40*33840Skarels 	} s_util;
41*33840Skarels 	union {
42*33840Skarels 		u_short s[2];
43*33840Skarels 		long	l;
44*33840Skarels 	} l_util;
45*33840Skarels 
46*33840Skarels 	for (;m && len; m = m->m_next) {
47*33840Skarels 		if (m->m_len == 0)
48*33840Skarels 			continue;
49*33840Skarels 		w = mtod(m, u_short *);
50*33840Skarels 		if (mlen == -1) {
51*33840Skarels 			/*
52*33840Skarels 			 * The first byte of this mbuf is the continuation
53*33840Skarels 			 * of a word spanning between this mbuf and the
54*33840Skarels 			 * last mbuf.
55*33840Skarels 			 *
56*33840Skarels 			 * s_util.c[0] is already saved when scanning previous
57*33840Skarels 			 * mbuf.
58*33840Skarels 			 */
59*33840Skarels 			s_util.c[1] = *(char *)w;
60*33840Skarels 			sum += s_util.s;
61*33840Skarels 			w = (u_short *)((char *)w + 1);
62*33840Skarels 			mlen = m->m_len - 1;
63*33840Skarels 			len--;
64*33840Skarels 		} else
65*33840Skarels 			mlen = m->m_len;
66*33840Skarels 		if (len < mlen)
67*33840Skarels 			mlen = len;
68*33840Skarels 		len -= mlen;
69*33840Skarels 		/*
70*33840Skarels 		 * Force to even boundary.
71*33840Skarels 		 */
72*33840Skarels 		if ((1 & (int) w) && (mlen > 0)) {
73*33840Skarels 			REDUCE;
74*33840Skarels 			sum <<= 8;
75*33840Skarels 			s_util.c[0] = *(u_char *)w;
76*33840Skarels 			w = (u_short *)((char *)w + 1);
77*33840Skarels 			mlen--;
78*33840Skarels 			byte_swapped = 1;
79*33840Skarels 		}
80*33840Skarels 		/*
81*33840Skarels 		 * Unroll the loop to make overhead from
82*33840Skarels 		 * branches &c small.
83*33840Skarels 		 */
84*33840Skarels 		while ((mlen -= 32) >= 0) {
85*33840Skarels 			sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
86*33840Skarels 			sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
87*33840Skarels 			sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
88*33840Skarels 			sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
89*33840Skarels 			w += 16;
90*33840Skarels 		}
91*33840Skarels 		mlen += 32;
92*33840Skarels 		while ((mlen -= 8) >= 0) {
93*33840Skarels 			sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
94*33840Skarels 			w += 4;
95*33840Skarels 		}
96*33840Skarels 		mlen += 8;
97*33840Skarels 		if (mlen == 0 && byte_swapped == 0)
98*33840Skarels 			continue;
99*33840Skarels 		REDUCE;
100*33840Skarels 		while ((mlen -= 2) >= 0) {
101*33840Skarels 			sum += *w++;
102*33840Skarels 		}
103*33840Skarels 		if (byte_swapped) {
104*33840Skarels 			REDUCE;
105*33840Skarels 			sum <<= 8;
106*33840Skarels 			byte_swapped = 0;
107*33840Skarels 			if (mlen == -1) {
108*33840Skarels 				s_util.c[1] = *(char *)w;
109*33840Skarels 				sum += s_util.s;
110*33840Skarels 				mlen = 0;
111*33840Skarels 			} else
112*33840Skarels 				mlen = -1;
113*33840Skarels 		} else if (mlen == -1)
114*33840Skarels 			s_util.c[0] = *(char *)w;
115*33840Skarels 	}
116*33840Skarels 	if (len)
117*33840Skarels 		printf("cksum: out of data\n");
118*33840Skarels 	if (mlen == -1) {
119*33840Skarels 		/* The last mbuf has odd # of bytes. Follow the
120*33840Skarels 		   standard (the odd byte may be shifted left by 8 bits
121*33840Skarels 		   or not as determined by endian-ness of the machine) */
122*33840Skarels 		s_util.c[1] = 0;
123*33840Skarels 		sum += s_util.s;
124*33840Skarels 	}
125*33840Skarels 	REDUCE;
126*33840Skarels 	return (~sum & 0xffff);
127*33840Skarels }
128