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