1/*	$OpenBSD: in_cksum.c,v 1.11 2022/02/01 15:30:10 miod Exp $	*/
2/*	$NetBSD: in_cksum.c,v 1.7 2003/07/15 02:54:48 lukem Exp $	*/
3
4/*
5 * Copyright 2001 Wasabi Systems, Inc.
6 * All rights reserved.
7 *
8 * Written by Simon Burge and Eduardo Horvath for Wasabi Systems, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *      This product includes software developed for the NetBSD Project by
21 *      Wasabi Systems, Inc.
22 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23 *    or promote products derived from this software without specific prior
24 *    written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/mbuf.h>
42#include <sys/socketvar.h>
43
44#include <netinet/in.h>
45#include <netinet/ip.h>
46#include <netinet/ip_var.h>
47
48/*
49 * Checksum routine for Internet Protocol family headers.
50 *
51 * This routine is very heavily used in the network
52 * code and should be modified for each CPU to be as fast as possible.
53 *
54 * PowerPC version.
55 */
56
57#define	REDUCE1		sum = (sum & 0xffff) + (sum >> 16)
58/* Two REDUCE1s is faster than REDUCE1; if (sum > 65535) sum -= 65536; */
59#define	REDUCE		{ REDUCE1; REDUCE1; }
60
61static __inline__ int
62in_cksum_internal(struct mbuf *m, int off, int len, u_int sum)
63{
64	uint8_t *w;
65	int mlen = 0;
66	int byte_swapped = 0;
67	int n;
68
69	union {
70		uint8_t  c[2];
71		uint16_t s;
72	} s_util;
73
74	for (;m && len; m = m->m_next) {
75		if (m->m_len == 0)
76			continue;
77		w = mtod(m, uint8_t *) + off;
78
79		/*
80		 * 'off' can only be non-zero on the first pass of this
81		 * loop when mlen != -1, so we don't need to worry about
82		 * 'off' in the if clause below.
83		 */
84		if (mlen == -1) {
85			/*
86			 * The first byte of this mbuf is the continuation
87			 * of a word spanning between this mbuf and the
88			 * last mbuf.
89			 *
90			 * s_util.c[0] is already saved when scanning previous
91			 * mbuf.
92			 */
93			s_util.c[1] = *w++;
94			sum += s_util.s;
95			mlen = m->m_len - 1;
96			len--;
97		} else {
98			mlen = m->m_len - off;
99			off = 0;
100		}
101		if (len < mlen)
102			mlen = len;
103		len -= mlen;
104
105		/*
106		 * Force to a word boundary.
107		 */
108		if ((3 & (long) w) && (mlen > 0)) {
109			if ((1 & (long) w)) {
110				REDUCE;
111				sum <<= 8;
112				s_util.c[0] = *w++;
113				mlen--;
114				byte_swapped = 1;
115			}
116			if ((2 & (long) w) && (mlen > 1)) {
117				/*
118				 * Since the `sum' may contain full 32 bit
119				 * value, we can't simply add any value.
120				 */
121				__asm volatile(
122				    "lhz 7,0(%1);"	/* load current data
123							   half word */
124				    "addc %0,%0,7;"	/* add to sum */
125				    "addze %0,%0;"	/* add carry bit */
126				    : "+r"(sum)
127				    : "b"(w)
128				    : "7");		/* clobber r7 */
129				w += 2;
130				mlen -= 2;
131			}
132		}
133
134		if (mlen >= 64) {
135			n = mlen >> 6;
136			__asm volatile(
137			    "addic 0,0,0;"		/* clear carry */
138			    "mtctr %1;"			/* load loop count */
139			    "1:"
140			    "lwz 7,4(%2);"		/* load current data
141							   word */
142			    "lwz 8,8(%2);"
143			    "lwz 9,12(%2);"
144			    "lwz 10,16(%2);"
145			    "adde %0,%0,7;"		/* add to sum */
146			    "adde %0,%0,8;"
147			    "adde %0,%0,9;"
148			    "adde %0,%0,10;"
149			    "lwz 7,20(%2);"
150			    "lwz 8,24(%2);"
151			    "lwz 9,28(%2);"
152			    "lwz 10,32(%2);"
153			    "adde %0,%0,7;"
154			    "adde %0,%0,8;"
155			    "adde %0,%0,9;"
156			    "adde %0,%0,10;"
157			    "lwz 7,36(%2);"
158			    "lwz 8,40(%2);"
159			    "lwz 9,44(%2);"
160			    "lwz 10,48(%2);"
161			    "adde %0,%0,7;"
162			    "adde %0,%0,8;"
163			    "adde %0,%0,9;"
164			    "adde %0,%0,10;"
165			    "lwz 7,52(%2);"
166			    "lwz 8,56(%2);"
167			    "lwz 9,60(%2);"
168			    "lwzu 10,64(%2);"
169			    "adde %0,%0,7;"
170			    "adde %0,%0,8;"
171			    "adde %0,%0,9;"
172			    "adde %0,%0,10;"
173			    "bdnz 1b;"			/* loop */
174			    "addze %0,%0;"		/* add carry bit */
175			    : "+r"(sum)
176			    : "r"(n), "b"(w - 4)
177			    : "7", "8", "9", "10");	/* clobber r7, r8, r9,
178							   r10 */
179			w += n * 64;
180			mlen -= n * 64;
181		}
182
183		if (mlen >= 8) {
184			n = mlen >> 3;
185			__asm volatile(
186			    "addic 0,0,0;"		/* clear carry */
187			    "mtctr %1;"			/* load loop count */
188			    "1:"
189			    "lwz 7,4(%2);"		/* load current data
190							   word */
191			    "lwzu 8,8(%2);"
192			    "adde %0,%0,7;"		/* add to sum */
193			    "adde %0,%0,8;"
194			    "bdnz 1b;"			/* loop */
195			    "addze %0,%0;"		/* add carry bit */
196			    : "+r"(sum)
197			    : "r"(n), "b"(w - 4)
198			    : "7", "8");		/* clobber r7, r8 */
199			w += n * 8;
200			mlen -= n * 8;
201		}
202
203		if (mlen == 0 && byte_swapped == 0)
204			continue;
205		REDUCE;
206
207		while ((mlen -= 2) >= 0) {
208			sum += *(uint16_t *)w;
209			w += 2;
210		}
211
212		if (byte_swapped) {
213			REDUCE;
214			sum <<= 8;
215			byte_swapped = 0;
216			if (mlen == -1) {
217				s_util.c[1] = *w;
218				sum += s_util.s;
219				mlen = 0;
220			} else
221				mlen = -1;
222		} else if (mlen == -1)
223			s_util.c[0] = *w;
224	}
225	if (len)
226		printf("cksum: out of data\n");
227	if (mlen == -1) {
228		/* The last mbuf has odd # of bytes. Follow the
229		   standard (the odd byte may be shifted left by 8 bits
230		   or not as determined by endian-ness of the machine) */
231		s_util.c[1] = 0;
232		sum += s_util.s;
233	}
234	REDUCE;
235	return (~sum & 0xffff);
236}
237
238int
239in_cksum(struct mbuf *m, int len)
240{
241
242	return (in_cksum_internal(m, 0, len, 0));
243}
244
245int
246in4_cksum(struct mbuf *m, uint8_t nxt, int off, int len)
247{
248	uint16_t *w;
249	u_int sum = 0;
250	union {
251		struct ipovly ipov;
252		u_int16_t w[10];
253	} u;
254
255	if (nxt != 0) {
256		/* pseudo header */
257		u.ipov.ih_x1[8] = 0;
258		u.ipov.ih_pr = nxt;
259		u.ipov.ih_len = htons(len);
260		u.ipov.ih_src = mtod(m, struct ip *)->ip_src;
261		u.ipov.ih_dst = mtod(m, struct ip *)->ip_dst;
262		w = u.w;
263		/* assumes sizeof(ipov) == 20 and first 8 bytes are zeroes */
264		sum += w[4]; sum += w[5]; sum += w[6];
265		sum += w[7]; sum += w[8]; sum += w[9];
266	}
267
268	/* skip unnecessary part */
269	while (m && off > 0) {
270		if (m->m_len > off)
271			break;
272		off -= m->m_len;
273		m = m->m_next;
274	}
275
276	return (in_cksum_internal(m, off, len, sum));
277}
278