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