xref: /original-bsd/sys/netiso/iso_chksum.c (revision 6a39c8ab)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)iso_chksum.c	7.6 (Berkeley) 08/28/91
8  */
9 
10 /***********************************************************
11 		Copyright IBM Corporation 1987
12 
13                       All Rights Reserved
14 
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of IBM not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22 
23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30 
31 ******************************************************************/
32 
33 /*
34  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35  */
36 /*
37  * $Header: iso_chksum.c,v 4.7 88/07/29 15:31:26 nhall Exp $
38  * $Source: /usr/argo/sys/netiso/RCS/iso_chksum.c,v $
39  *
40  * ISO CHECKSUM
41  *
42  * The checksum generation and check routines are here.
43  * The checksum is 2 bytes such that the sum of all the bytes b(i) == 0
44  * and the sum of i * b(i) == 0.
45  * The whole thing is complicated by the fact that the data are in mbuf
46  * chains.
47  * Furthermore, there is the possibility of wraparound in the running
48  * sums after adding up 4102 octets.  In order to avoid doing a mod
49  * operation after EACH add, we have restricted this implementation to
50  * negotiating a maximum of 4096-octets per TPDU (for the transport layer).
51  * The routine iso_check_csum doesn't need to know where the checksum
52  * octets are.
53  * The routine iso_gen_csum takes a pointer to an mbuf chain (logically
54  * a chunk of data), an offset into the chunk at which the 2 octets are to
55  * be stuffed, and the length of the chunk.  The 2 octets have to be
56  * logically adjacent, but may be physically located in separate mbufs.
57  */
58 
59 #ifdef ISO
60 #include "argo_debug.h"
61 #include "param.h"
62 #include "mbuf.h"
63 #endif ISO
64 
65 #ifndef MNULL
66 #define MNULL (struct mbuf *)0
67 #endif MNULL
68 
69 /*
70  * FUNCTION:	iso_check_csum
71  *
72  * PURPOSE:		To check the checksum of the packet in the mbuf chain (m).
73  * 				The total length of the packet is (len).
74  * 				Called from tp_input() and clnp_intr()
75  *
76  * RETURNS:		 TRUE (something non-zero) if there is a checksum error,
77  * 			 	 FALSE if there was NO checksum error.
78  *
79  * SIDE EFFECTS:  none
80  *
81  * NOTES:		 It might be possible to gain something by optimizing
82  *               this routine (unrolling loops, etc). But it is such
83  *				 a horrible thing to fiddle with anyway, it probably
84  *				 isn't worth it.
85  */
86 int
87 iso_check_csum(m, len)
88 	struct mbuf *m;
89 	int len;
90 {
91 	register u_char *p = mtod(m, u_char *);
92 	register u_long c0=0, c1=0;
93 	register int i=0;
94 	int cum = 0; /* cumulative length */
95 	int l;
96 
97 	l = len;
98 	len = MIN(m->m_len, len);
99 	i = 0;
100 
101 	IFDEBUG(D_CHKSUM)
102 		printf("iso_check_csum: m x%x, l x%x, m->m_len x%x\n", m, l, m->m_len);
103 	ENDDEBUG
104 
105 	while( i<l ) {
106 		cum += len;
107 		while (i<cum) {
108 			c0 = c0 + *(p++);
109 			c1 += c0;
110 			i++;
111 		}
112 		if(i < l) {
113 			m = m->m_next;
114 			IFDEBUG(D_CHKSUM)
115 				printf("iso_check_csum: new mbuf\n");
116 				if(l-i < m->m_len)
117 					printf(
118 					"bad mbuf chain in check csum l 0x%x i 0x%x m_data 0x%x",
119 						l,i,m->m_data);
120 			ENDDEBUG
121 			ASSERT( m != MNULL);
122 			len = MIN( m->m_len, l-i);
123 			p = mtod(m, u_char *);
124 		}
125 	}
126 	if ( ((int)c0 % 255) || ((int)c1 % 255) ) {
127 		IFDEBUG(D_CHKSUM)
128 			printf("BAD iso_check_csum l 0x%x cum 0x%x len 0x%x, i 0x%x",
129 				l, cum, len, i);
130 		ENDDEBUG
131 		return ((int)c0 % 255)<<8 | ((int)c1 % 255);
132 	}
133 	return 0;
134 }
135 
136 /*
137  * FUNCTION:	iso_gen_csum
138  *
139  * PURPOSE:		To generate the checksum of the packet in the mbuf chain (m).
140  * 				The first of the 2 (logically) adjacent checksum bytes
141  *				(x and y) go at offset (n).
142  * 				(n) is an offset relative to the beginning of the data,
143  *				not the beginning of the mbuf.
144  * 				(l) is the length of the total mbuf chain's data.
145  * 				Called from tp_emit(), tp_error_emit()
146  *				clnp_emit_er(), clnp_forward(), clnp_output().
147  *
148  * RETURNS:		Rien
149  *
150  * SIDE EFFECTS: Puts the 2 checksum bytes into the packet.
151  *
152  * NOTES:		Ditto the note for iso_check_csum().
153  */
154 
155 void
156 iso_gen_csum(m,n,l)
157 	struct mbuf *m;
158 	int n; /* offset of 2 checksum bytes */
159 	int l;
160 {
161 	register u_char *p = mtod(m, u_char *);
162 	register int c0=0, c1=0;
163 	register int i=0;
164 	int loc = n++, len=0; /* n is position, loc is offset */
165 	u_char *xloc;
166 	u_char *yloc;
167 	int cum=0;	/* cum == cumulative length */
168 
169 	IFDEBUG(D_CHKSUM)
170 		printf("enter gen csum m 0x%x n 0x%x l 0x%x\n",m, n-1 ,l );
171 	ENDDEBUG
172 
173 	while(i < l) {
174 		len = MIN(m->m_len, CLBYTES);
175 		/* RAH: don't cksum more than l bytes */
176 		len = MIN(len, l - i);
177 
178 		cum +=len;
179 		p = mtod(m, u_char *);
180 
181 		if(loc>=0) {
182 			if (loc < len) {
183 				xloc = loc + mtod(m, u_char *);
184 				IFDEBUG(D_CHKSUM)
185 					printf("1: zeroing xloc 0x%x loc 0x%x\n",xloc, loc );
186 				ENDDEBUG
187 				*xloc = (u_char)0;
188 				if (loc+1 < len) {
189 					/* both xloc and yloc are in same mbuf */
190 					yloc = 1  + xloc;
191 					IFDEBUG(D_CHKSUM)
192 						printf("2: zeroing yloc 0x%x loc 0x%x\n",yloc, loc );
193 					ENDDEBUG
194 					*yloc = (u_char)0;
195 				} else {
196 					/* crosses boundary of mbufs */
197 					yloc = mtod(m->m_next, u_char *);
198 					IFDEBUG(D_CHKSUM)
199 						printf("3: zeroing yloc 0x%x \n",yloc );
200 					ENDDEBUG
201 					*yloc = (u_char)0;
202 				}
203 			}
204 			loc -= len;
205 		}
206 
207 		while(i < cum) {
208 			c0 = (c0 + *p);
209 			c1 += c0 ;
210 			i++;
211 			p++;
212 		}
213 		m = m->m_next;
214 	}
215 	IFDEBUG(D_CHKSUM)
216 		printf("gen csum final xloc 0x%x yloc 0x%x\n",xloc, yloc );
217 	ENDDEBUG
218 
219 	c1 = (((c0 * (l-n))-c1)%255) ;
220 	*xloc = (u_char) ((c1 < 0)? c1+255 : c1);
221 
222 	c1 = (-(int)(c1+c0))%255;
223 	*yloc = (u_char) (c1 < 0? c1 + 255 : c1);
224 
225 	IFDEBUG(D_CHKSUM)
226 		printf("gen csum end \n");
227 	ENDDEBUG
228 }
229 
230 /*
231  * FUNCTION:	m_datalen
232  *
233  * PURPOSE:		returns length of the mbuf chain.
234  * 				used all over the iso code.
235  *
236  * RETURNS:		integer
237  *
238  * SIDE EFFECTS: none
239  *
240  * NOTES:
241  */
242 
243 int
244 m_datalen (m)
245 	register struct mbuf *m;
246 {
247 	register int datalen;
248 
249 	for (datalen = 0; m; m = m->m_next)
250 		datalen += m->m_len;
251 	return datalen;
252 }
253 
254 int
255 m_compress(in, out)
256 	register struct mbuf *in, **out;
257 {
258 	register 	int datalen = 0;
259 	int	s = splimp();
260 
261 	if( in->m_next == MNULL ) {
262 		*out = in;
263 		IFDEBUG(D_REQUEST)
264 			printf("m_compress returning 0x%x: A\n", in->m_len);
265 		ENDDEBUG
266 		splx(s);
267 		return in->m_len;
268 	}
269 	MGET((*out), M_DONTWAIT, MT_DATA);
270 	if((*out) == MNULL) {
271 		*out = in;
272 		IFDEBUG(D_REQUEST)
273 			printf("m_compress returning -1: B\n");
274 		ENDDEBUG
275 		splx(s);
276 		return -1;
277 	}
278 	(*out)->m_len = 0;
279 	(*out)->m_act = MNULL;
280 
281 	while (in) {
282 		IFDEBUG(D_REQUEST)
283 			printf("m_compress in 0x%x *out 0x%x\n", in, *out);
284 			printf("m_compress in: len 0x%x, off 0x%x\n", in->m_len, in->m_data);
285 			printf("m_compress *out: len 0x%x, off 0x%x\n", (*out)->m_len,
286 				(*out)->m_data);
287 		ENDDEBUG
288 		if (in->m_flags & M_EXT) {
289 			ASSERT(in->m_len == 0);
290 		}
291 		if ( in->m_len == 0) {
292 			in = in->m_next;
293 			continue;
294 		}
295 		if (((*out)->m_flags & M_EXT) == 0) {
296 			int len;
297 
298 			len = M_TRAILINGSPACE(*out);
299 			len = MIN(len, in->m_len);
300 			datalen += len;
301 
302 			IFDEBUG(D_REQUEST)
303 				printf("m_compress copying len %d\n", len);
304 			ENDDEBUG
305 			bcopy(mtod(in, caddr_t), mtod((*out), caddr_t) + (*out)->m_len,
306 						(unsigned)len);
307 
308 			(*out)->m_len += len;
309 			in->m_len -= len;
310 			continue;
311 		} else {
312 			/* (*out) is full */
313 			if(( (*out)->m_next = m_get(M_DONTWAIT, MT_DATA) ) == MNULL) {
314 				m_freem(*out);
315 				*out = in;
316 				IFDEBUG(D_REQUEST)
317 					printf("m_compress returning -1: B\n");
318 				ENDDEBUG
319 				splx(s);
320 				return -1;
321 			}
322 			(*out)->m_len = 0;
323 			(*out)->m_act = MNULL;
324 			*out = (*out)->m_next;
325 		}
326 	}
327 	m_freem(in);
328 	IFDEBUG(D_REQUEST)
329 		printf("m_compress returning 0x%x: A\n", datalen);
330 	ENDDEBUG
331 	splx(s);
332 	return datalen;
333 }
334