xref: /openbsd/sys/arch/alpha/alpha/in_cksum.c (revision fe1ad185)
1*fe1ad185Smiod /*	$OpenBSD: in_cksum.c,v 1.10 2022/02/01 15:30:10 miod Exp $	*/
23a630e3fSniklas /*	$NetBSD: in_cksum.c,v 1.4 1996/11/13 21:13:06 cgd Exp $	*/
3417eba8cSderaadt 
4417eba8cSderaadt /*
5417eba8cSderaadt  * Copyright (c) 1988, 1992, 1993
6417eba8cSderaadt  *	The Regents of the University of California.  All rights reserved.
7417eba8cSderaadt  * Copyright (c) 1996
8417eba8cSderaadt  *	Matt Thomas <matt@3am-software.com>
9417eba8cSderaadt  *
10417eba8cSderaadt  * Redistribution and use in source and binary forms, with or without
11417eba8cSderaadt  * modification, are permitted provided that the following conditions
12417eba8cSderaadt  * are met:
13417eba8cSderaadt  * 1. Redistributions of source code must retain the above copyright
14417eba8cSderaadt  *    notice, this list of conditions and the following disclaimer.
15417eba8cSderaadt  * 2. Redistributions in binary form must reproduce the above copyright
16417eba8cSderaadt  *    notice, this list of conditions and the following disclaimer in the
17417eba8cSderaadt  *    documentation and/or other materials provided with the distribution.
1829295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
19417eba8cSderaadt  *    may be used to endorse or promote products derived from this software
20417eba8cSderaadt  *    without specific prior written permission.
21417eba8cSderaadt  *
22417eba8cSderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23417eba8cSderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24417eba8cSderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25417eba8cSderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26417eba8cSderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27417eba8cSderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28417eba8cSderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29417eba8cSderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30417eba8cSderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31417eba8cSderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32417eba8cSderaadt  * SUCH DAMAGE.
33417eba8cSderaadt  *
34417eba8cSderaadt  *	@(#)in_cksum.c	8.1 (Berkeley) 6/10/93
35417eba8cSderaadt  */
36417eba8cSderaadt 
37417eba8cSderaadt #include <sys/param.h>
38417eba8cSderaadt #include <sys/mbuf.h>
39417eba8cSderaadt #include <sys/systm.h>
40b1fc721fSbrad #include <sys/socketvar.h>
41417eba8cSderaadt #include <netinet/in.h>
42b1fc721fSbrad #include <netinet/ip.h>
43b1fc721fSbrad #include <netinet/ip_var.h>
4450ce9ee0Sniklas 
45417eba8cSderaadt /*
46417eba8cSderaadt  * Checksum routine for Internet Protocol family headers
47417eba8cSderaadt  *    (Portable Alpha version).
48417eba8cSderaadt  *
49417eba8cSderaadt  * This routine is very heavily used in the network
50417eba8cSderaadt  * code and should be modified for each CPU to be as fast as possible.
51417eba8cSderaadt  */
52417eba8cSderaadt 
53417eba8cSderaadt #define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
54417eba8cSderaadt #define REDUCE32							  \
55417eba8cSderaadt     {									  \
56417eba8cSderaadt 	q_util.q = sum;							  \
57417eba8cSderaadt 	sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3];	  \
58417eba8cSderaadt     }
59417eba8cSderaadt #define REDUCE16							  \
60417eba8cSderaadt     {									  \
61417eba8cSderaadt 	q_util.q = sum;							  \
62417eba8cSderaadt 	l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
63417eba8cSderaadt 	sum = l_util.s[0] + l_util.s[1];				  \
64417eba8cSderaadt 	ADDCARRY(sum);							  \
65417eba8cSderaadt     }
66417eba8cSderaadt 
67417eba8cSderaadt static const u_int32_t in_masks[] = {
68417eba8cSderaadt 	/*0 bytes*/ /*1 byte*/	/*2 bytes*/ /*3 bytes*/
69417eba8cSderaadt 	0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF,	/* offset 0 */
70417eba8cSderaadt 	0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00,	/* offset 1 */
71417eba8cSderaadt 	0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000,	/* offset 2 */
72417eba8cSderaadt 	0x00000000, 0xFF000000, 0xFF000000, 0xFF000000,	/* offset 3 */
73417eba8cSderaadt };
74417eba8cSderaadt 
75417eba8cSderaadt union l_util {
76417eba8cSderaadt 	u_int16_t s[2];
77417eba8cSderaadt 	u_int32_t l;
78417eba8cSderaadt };
79417eba8cSderaadt union q_util {
80417eba8cSderaadt 	u_int16_t s[4];
81417eba8cSderaadt 	u_int32_t l[2];
82417eba8cSderaadt 	u_int64_t q;
83417eba8cSderaadt };
84417eba8cSderaadt 
85b1fc721fSbrad static u_int64_t
in_cksumdata(caddr_t buf,int len)86b1fc721fSbrad in_cksumdata(caddr_t buf, int len)
87417eba8cSderaadt {
88417eba8cSderaadt 	const u_int32_t *lw = (u_int32_t *) buf;
89417eba8cSderaadt 	u_int64_t sum = 0;
90417eba8cSderaadt 	u_int64_t prefilled;
91417eba8cSderaadt 	int offset;
92417eba8cSderaadt 	union q_util q_util;
93417eba8cSderaadt 
94417eba8cSderaadt 	if ((3 & (long) lw) == 0 && len == 20) {
95417eba8cSderaadt 	     sum = (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4];
96417eba8cSderaadt 	     REDUCE32;
97417eba8cSderaadt 	     return sum;
98417eba8cSderaadt 	}
99417eba8cSderaadt 
100417eba8cSderaadt 	if ((offset = 3 & (long) lw) != 0) {
101417eba8cSderaadt 		const u_int32_t *masks = in_masks + (offset << 2);
102417eba8cSderaadt 		lw = (u_int32_t *) (((long) lw) - offset);
103417eba8cSderaadt 		sum = *lw++ & masks[len >= 3 ? 3 : len];
104417eba8cSderaadt 		len -= 4 - offset;
105417eba8cSderaadt 		if (len <= 0) {
106417eba8cSderaadt 			REDUCE32;
107417eba8cSderaadt 			return sum;
108417eba8cSderaadt 		}
109417eba8cSderaadt 	}
110417eba8cSderaadt #if 0
111417eba8cSderaadt 	/*
112417eba8cSderaadt 	 * Force to cache line boundary.
113417eba8cSderaadt 	 */
114417eba8cSderaadt 	offset = 32 - (0x1f & (long) lw);
115417eba8cSderaadt 	if (offset < 32 && len > offset) {
116417eba8cSderaadt 		len -= offset;
117417eba8cSderaadt 		if (4 & offset) {
118417eba8cSderaadt 			sum += (u_int64_t) lw[0];
119417eba8cSderaadt 			lw += 1;
120417eba8cSderaadt 		}
121417eba8cSderaadt 		if (8 & offset) {
122417eba8cSderaadt 			sum += (u_int64_t) lw[0] + lw[1];
123417eba8cSderaadt 			lw += 2;
124417eba8cSderaadt 		}
125417eba8cSderaadt 		if (16 & offset) {
126417eba8cSderaadt 			sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
127417eba8cSderaadt 			lw += 4;
128417eba8cSderaadt 		}
129417eba8cSderaadt 	}
130417eba8cSderaadt #endif
131417eba8cSderaadt 	/*
132417eba8cSderaadt 	 * access prefilling to start load of next cache line.
133417eba8cSderaadt 	 * then add current cache line
134417eba8cSderaadt 	 * save result of prefilling for loop iteration.
135417eba8cSderaadt 	 */
136417eba8cSderaadt 	prefilled = lw[0];
137417eba8cSderaadt 	while ((len -= 32) >= 4) {
138417eba8cSderaadt 		u_int64_t prefilling = lw[8];
139417eba8cSderaadt 		sum += prefilled + lw[1] + lw[2] + lw[3]
140417eba8cSderaadt 			+ lw[4] + lw[5] + lw[6] + lw[7];
141417eba8cSderaadt 		lw += 8;
142417eba8cSderaadt 		prefilled = prefilling;
143417eba8cSderaadt 	}
144417eba8cSderaadt 	if (len >= 0) {
145417eba8cSderaadt 		sum += prefilled + lw[1] + lw[2] + lw[3]
146417eba8cSderaadt 			+ lw[4] + lw[5] + lw[6] + lw[7];
147417eba8cSderaadt 		lw += 8;
148417eba8cSderaadt 	} else {
149417eba8cSderaadt 		len += 32;
150417eba8cSderaadt 	}
151417eba8cSderaadt 	while ((len -= 16) >= 0) {
152417eba8cSderaadt 		sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
153417eba8cSderaadt 		lw += 4;
154417eba8cSderaadt 	}
155417eba8cSderaadt 	len += 16;
156417eba8cSderaadt 	while ((len -= 4) >= 0) {
157417eba8cSderaadt 		sum += (u_int64_t) *lw++;
158417eba8cSderaadt 	}
159417eba8cSderaadt 	len += 4;
160417eba8cSderaadt 	if (len > 0)
161417eba8cSderaadt 		sum += (u_int64_t) (in_masks[len] & *lw);
162417eba8cSderaadt 	REDUCE32;
163417eba8cSderaadt 	return sum;
164417eba8cSderaadt }
165417eba8cSderaadt 
166417eba8cSderaadt int
in_cksum(struct mbuf * m,int len)167b1fc721fSbrad in_cksum(struct mbuf *m, int len)
168417eba8cSderaadt {
169b1fc721fSbrad 	u_int64_t sum = 0;
170b1fc721fSbrad 	int mlen = 0;
171b1fc721fSbrad 	int clen = 0;
172b1fc721fSbrad 	caddr_t addr;
173417eba8cSderaadt 	union l_util l_util;
1743a630e3fSniklas 	union q_util q_util;
175417eba8cSderaadt 
176417eba8cSderaadt 	for (; m && len; m = m->m_next) {
177417eba8cSderaadt 		if (m->m_len == 0)
178417eba8cSderaadt 			continue;
179417eba8cSderaadt 		mlen = m->m_len;
180417eba8cSderaadt 		if (len < mlen)
181417eba8cSderaadt 			mlen = len;
182417eba8cSderaadt 		addr = mtod(m, caddr_t);
183417eba8cSderaadt 		if ((clen ^ (long) addr) & 1)
184417eba8cSderaadt 		    sum += in_cksumdata(addr, mlen) << 8;
185417eba8cSderaadt 		else
186417eba8cSderaadt 		    sum += in_cksumdata(addr, mlen);
187417eba8cSderaadt 
188417eba8cSderaadt 		clen += mlen;
189417eba8cSderaadt 		len -= mlen;
190417eba8cSderaadt 	}
191417eba8cSderaadt 	REDUCE16;
192417eba8cSderaadt 	return (~sum & 0xffff);
193417eba8cSderaadt }
194b1fc721fSbrad 
195b1fc721fSbrad int
in4_cksum(struct mbuf * m,u_int8_t nxt,int off,int len)196b1fc721fSbrad in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len)
197b1fc721fSbrad {
198b1fc721fSbrad 	u_int64_t sum = 0;
199b1fc721fSbrad 	int mlen = 0;
200b1fc721fSbrad 	int clen = 0;
201b1fc721fSbrad 	caddr_t addr;
202b1fc721fSbrad 	union q_util q_util;
203b1fc721fSbrad 	union l_util l_util;
204b1fc721fSbrad 	struct ipovly ipov;
205b1fc721fSbrad 
206b1fc721fSbrad 	if (nxt != 0) {
207070da95bSmiod #ifdef DEBUG
208b1fc721fSbrad 		/* pseudo header */
209b1fc721fSbrad 		if (off < sizeof(struct ipovly))
210b1fc721fSbrad 			panic("in4_cksum: offset too short");
211b1fc721fSbrad 		if (m->m_len < sizeof(struct ip))
212b1fc721fSbrad 			panic("in4_cksum: bad mbuf chain");
213070da95bSmiod #endif
214b1fc721fSbrad 
215*fe1ad185Smiod 		ipov.ih_x1[8] = 0;
216b1fc721fSbrad 		ipov.ih_pr = nxt;
217*fe1ad185Smiod 		ipov.ih_len = htons(len);
218b1fc721fSbrad 		ipov.ih_src = mtod(m, struct ip *)->ip_src;
219b1fc721fSbrad 		ipov.ih_dst = mtod(m, struct ip *)->ip_dst;
220b1fc721fSbrad 
221*fe1ad185Smiod 		/* first 8 bytes are zeroes */
222*fe1ad185Smiod 		sum += in_cksumdata((caddr_t) &ipov + 8, sizeof(ipov) - 8);
223b1fc721fSbrad 	}
224b1fc721fSbrad 
225b1fc721fSbrad 	/* skip over unnecessary part */
226b1fc721fSbrad 	while (m != NULL && off > 0) {
227b1fc721fSbrad 		if (m->m_len > off)
228b1fc721fSbrad 			break;
229b1fc721fSbrad 		off -= m->m_len;
230b1fc721fSbrad 		m = m->m_next;
231b1fc721fSbrad 	}
232b1fc721fSbrad 
233b1fc721fSbrad 	for (; m && len; m = m->m_next, off = 0) {
234b1fc721fSbrad 		if (m->m_len == 0)
235b1fc721fSbrad 			continue;
236b1fc721fSbrad 		mlen = m->m_len - off;
237b1fc721fSbrad 		if (len < mlen)
238b1fc721fSbrad 			mlen = len;
239b1fc721fSbrad 		addr = mtod(m, caddr_t) + off;
240b1fc721fSbrad 		if ((clen ^ (long) addr) & 1)
241b1fc721fSbrad 			sum += in_cksumdata(addr, mlen) << 8;
242b1fc721fSbrad  		else
243b1fc721fSbrad 			sum += in_cksumdata(addr, mlen);
244b1fc721fSbrad 
245b1fc721fSbrad  		clen += mlen;
246b1fc721fSbrad  		len -= mlen;
247b1fc721fSbrad 	}
248b1fc721fSbrad 	REDUCE16;
249b1fc721fSbrad 	return (~sum & 0xffff);
250b1fc721fSbrad }
251