xref: /original-bsd/sys/tahoe/tahoe/in_cksum.c (revision f3c03cba)
1 /*
2  * Copyright (c) 1982, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)in_cksum.c	7.6 (Berkeley) 12/16/90
8  */
9 
10 #include "sys/param.h"
11 #include "sys/mbuf.h"
12 
13 /*
14  * Checksum routine for Internet Protocol family headers (CCI 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)  { if ((x) > 65535) (x) -= 65535; }
21 #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
22 
23 #define ADD(n)	asm("adwc n (r10),r9")
24 #define MOP	asm("adwc $0,r9")
25 #define BOTCH	asm("addl2 r7,r9")
26 
27 in_cksum(m, len)
28 	register struct mbuf *m;
29 	register int len;
30 {
31 	register u_short *w;		/* On CCI, known to be r10 */
32 	register int sum = 0;		/* On CCI, known to be r9 */
33 	register int mlen = 0;
34 #ifndef lint
35 	register int ClearCarry = 0;	/* On CCI, known to be r7; see BOTCH */
36 #endif
37 	int byte_swapped = 0;
38 
39 	union {
40 		char	c[2];
41 		u_short	s;
42 	} s_util;
43 	union {
44 		u_short s[2];
45 		long	l;
46 	} l_util;
47 
48 	for (;m && len; m = m->m_next) {
49 		if (m->m_len == 0)
50 			continue;
51 		w = mtod(m, u_short *);
52 		if (mlen == -1) {
53 			/*
54 			 * The first byte of this mbuf is the continuation
55 			 * of a word spanning between this mbuf and the
56 			 * last mbuf.
57 			 *
58 			 * s_util.c[0] is already saved when scanning previous
59 			 * mbuf.  sum was REDUCEd when we found mlen == -1.
60 			 */
61 			s_util.c[1] = *(char *)w;
62 			sum += s_util.s;
63 			w = (u_short *)((char *)w + 1);
64 			mlen = m->m_len - 1;
65 			len--;
66 		} else
67 			mlen = m->m_len;
68 		if (len < mlen)
69 			mlen = len;
70 		len -= mlen;
71 		/*
72 		 * Force to long boundary so we do longword aligned
73 		 * memory operations.
74 		 */
75 		if (3 & (int) w) {
76 			REDUCE;
77 			if ((1 & (int) w) && (mlen > 0)) {
78 				sum <<= 8;
79 				s_util.c[0] = *(char *)w;
80 				w = (u_short *)((char *)w + 1);
81 				mlen--;
82 				byte_swapped = 1;
83 			}
84 			if ((2 & (int) w) && (mlen >= 2)) {
85 				sum += *w++;
86 				mlen -= 2;
87 			}
88 		}
89 		/*
90 		 * Do as much of the checksum as possible 32 bits at at time.
91 		 * In fact, this loop is unrolled to make overhead from
92 		 * branches &c small.
93 		 */
94 		while ((mlen -= 32) >= 0) {
95 			/*
96 			 * The loop construct clears carry for us
97 			 * on vaxen, however, on the CCI machine subtracting
98 			 * a small postive number from a larger one doesn't.
99 			 *
100 			 * Doing a bicpsw is very slow (slows down the routine
101 			 * by a factor of 2); explicitly adding an immediate
102 			 * 0 to a register is optimized out; so we fake out
103 			 * the optimizer and add a register whose contents
104 			 * is always zero.
105 			 */
106 			BOTCH;
107 			ADD(0); ADD(4); ADD(8); ADD(12);
108 			ADD(16); ADD(20); ADD(24); ADD(28);
109 			MOP; w += 16;
110 		}
111 		mlen += 32;
112 		while ((mlen -= 8) >= 0) {
113 			BOTCH;
114 			ADD(0); ADD(4);
115 			MOP;
116 			w += 4;
117 		}
118 		mlen += 8;
119 		if (mlen == 0 && byte_swapped == 0)
120 			continue;	/* worth 1% maybe ?? */
121 		REDUCE;
122 		while ((mlen -= 2) >= 0) {
123 			sum += *w++;
124 		}
125 		if (byte_swapped) {
126 			sum <<= 8;
127 			byte_swapped = 0;
128 			if (mlen == -1) {
129 				s_util.c[1] = *(char *)w;
130 				sum += s_util.s;
131 				mlen = 0;
132 			} else
133 				mlen = -1;
134 		} else if (mlen == -1)
135 			/*
136 			 * This mbuf has odd number of bytes.
137 			 * There could be a word split betwen
138 			 * this mbuf and the next mbuf.
139 			 * Save the last byte (to prepend to next mbuf).
140 			 */
141 			s_util.c[0] = *(char *)w;
142 	}
143 	if (len)
144 		printf("cksum: out of data\n");
145 	if (mlen == -1) {
146 		/* The last mbuf has odd # of bytes. Follow the
147 		   standard (the odd byte is shifted left by 8 bits) */
148 		s_util.c[1] = 0;
149 		sum += s_util.s;
150 	}
151 	REDUCE;
152 	return (~sum & 0xffff);
153 }
154