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