xref: /original-bsd/sys/netiso/iso_chksum.c (revision 95b555db)
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.5 (Berkeley) 05/06/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 struct mbuf  *
231 m_append(head, m)
232 	struct mbuf *head, *m;
233 {
234 	register struct mbuf *n;
235 
236 	if (m == 0)
237 		return head;
238 	if (head == 0)
239 		return m;
240 	n = head;
241 	while (n->m_next)
242 		n = n->m_next;
243 	n->m_next = m;
244 	return head;
245 }
246 /*
247  * FUNCTION:	m_datalen
248  *
249  * PURPOSE:		returns length of the mbuf chain.
250  * 				used all over the iso code.
251  *
252  * RETURNS:		integer
253  *
254  * SIDE EFFECTS: none
255  *
256  * NOTES:
257  */
258 
259 int
260 m_datalen (morig)
261 	struct mbuf *morig;
262 {
263 	int	s = splimp();
264 	register struct mbuf *n=morig;
265 	register int datalen = 0;
266 
267 	if( morig == (struct mbuf *)0)
268 		return 0;
269 	for(;;) {
270 		datalen += n->m_len;
271 		if (n->m_next == (struct mbuf *)0 ) {
272 			break;
273 		}
274 		n = n->m_next;
275 	}
276 	splx(s);
277 	return datalen;
278 }
279 
280 int
281 m_compress(in, out)
282 	register struct mbuf *in, **out;
283 {
284 	register 	int datalen = 0;
285 	int	s = splimp();
286 
287 	if( in->m_next == MNULL ) {
288 		*out = in;
289 		IFDEBUG(D_REQUEST)
290 			printf("m_compress returning 0x%x: A\n", in->m_len);
291 		ENDDEBUG
292 		splx(s);
293 		return in->m_len;
294 	}
295 	MGET((*out), M_DONTWAIT, MT_DATA);
296 	if((*out) == MNULL) {
297 		*out = in;
298 		IFDEBUG(D_REQUEST)
299 			printf("m_compress returning -1: B\n");
300 		ENDDEBUG
301 		splx(s);
302 		return -1;
303 	}
304 	(*out)->m_len = 0;
305 	(*out)->m_act = MNULL;
306 
307 	while (in) {
308 		IFDEBUG(D_REQUEST)
309 			printf("m_compress in 0x%x *out 0x%x\n", in, *out);
310 			printf("m_compress in: len 0x%x, off 0x%x\n", in->m_len, in->m_data);
311 			printf("m_compress *out: len 0x%x, off 0x%x\n", (*out)->m_len,
312 				(*out)->m_data);
313 		ENDDEBUG
314 		if (in->m_flags & M_EXT) {
315 			ASSERT(in->m_len == 0);
316 		}
317 		if ( in->m_len == 0) {
318 			in = in->m_next;
319 			continue;
320 		}
321 		if (((*out)->m_flags & M_EXT) == 0) {
322 			int len;
323 
324 			len = M_TRAILINGSPACE(*out);
325 			len = MIN(len, in->m_len);
326 			datalen += len;
327 
328 			IFDEBUG(D_REQUEST)
329 				printf("m_compress copying len %d\n", len);
330 			ENDDEBUG
331 			bcopy(mtod(in, caddr_t), mtod((*out), caddr_t) + (*out)->m_len,
332 						(unsigned)len);
333 
334 			(*out)->m_len += len;
335 			in->m_len -= len;
336 			continue;
337 		} else {
338 			/* (*out) is full */
339 			if(( (*out)->m_next = m_get(M_DONTWAIT, MT_DATA) ) == MNULL) {
340 				m_freem(*out);
341 				*out = in;
342 				IFDEBUG(D_REQUEST)
343 					printf("m_compress returning -1: B\n");
344 				ENDDEBUG
345 				splx(s);
346 				return -1;
347 			}
348 			(*out)->m_len = 0;
349 			(*out)->m_act = MNULL;
350 			*out = (*out)->m_next;
351 		}
352 	}
353 	m_freem(in);
354 	IFDEBUG(D_REQUEST)
355 		printf("m_compress returning 0x%x: A\n", datalen);
356 	ENDDEBUG
357 	splx(s);
358 	return datalen;
359 }
360