xref: /original-bsd/sys/i386/i386/in_cksum.c (revision c8089215)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  * from tahoe:	in_cksum.c	1.2	86/01/05
8  *	@(#)in_cksum.c	1.3 (Berkeley) 01/19/91
9  */
10 
11 #include "param.h"
12 #include "sys/mbuf.h"
13 #include "netinet/in.h"
14 #include "netinet/in_systm.h"
15 
16 /*
17  * Checksum routine for Internet Protocol family headers.
18  *
19  * This routine is very heavily used in the network
20  * code and should be modified for each CPU to be as fast as possible.
21  *
22  * This implementation is 386 version.
23  */
24 
25 #undef	ADDCARRY
26 #define ADDCARRY(sum)  {				\
27 			if (sum & 0xffff0000) {		\
28 				sum &= 0xffff;		\
29 				sum++;			\
30 			}				\
31 		}
32 in_cksum(m, len)
33 	register struct mbuf *m;
34 	register int len;
35 {
36 	union word {
37 		char	c[2];
38 		u_short	s;
39 	} u;
40 	register u_short *w;
41 	register int sum = 0;
42 	register int mlen = 0;
43 
44 	for (;m && len; m = m->m_next) {
45 		if (m->m_len == 0)
46 			continue;
47 		w = mtod(m, u_short *);
48 		if (mlen == -1) {
49 			/*
50 			 * The first byte of this mbuf is the continuation
51 			 * of a word spanning between this mbuf and the
52 			 * last mbuf.
53 			 */
54 
55 			/* u.c[0] is already saved when scanning previous
56 			 * mbuf.
57 			 */
58 			u.c[1] = *(u_char *)w;
59 			sum += u.s;
60 			ADDCARRY(sum);
61 			w = (u_short *)((char *)w + 1);
62 			mlen = m->m_len - 1;
63 			len--;
64 		} else
65 			mlen = m->m_len;
66 
67 		if (len < mlen)
68 			mlen = len;
69 		len -= mlen;
70 
71 		/*
72 		 * add by words.
73 		 */
74 		while ((mlen -= 2) >= 0) {
75 			if ((int)w & 0x1) {
76 				/* word is not aligned */
77 				u.c[0] = *(char *)w;
78 				u.c[1] = *((char *)w+1);
79 				sum += u.s;
80 				w++;
81 			} else
82 				sum += *w++;
83 			ADDCARRY(sum);
84 		}
85 		if (mlen == -1)
86 			/*
87 			 * This mbuf has odd number of bytes.
88 			 * There could be a word split betwen
89 			 * this mbuf and the next mbuf.
90 			 * Save the last byte (to prepend to next mbuf).
91 			 */
92 			u.c[0] = *(u_char *)w;
93 	}
94 	if (len)
95 		printf("cksum: out of data\n");
96 	if (mlen == -1) {
97 		/* The last mbuf has odd # of bytes. Follow the
98 		   standard (the odd byte is shifted left by 8 bits) */
99 		u.c[1] = 0;
100 		sum += u.s;
101 		ADDCARRY(sum);
102 	}
103 	return (~sum & 0xffff);
104 }
105