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