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