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 #ifndef lint 51 static 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 */ 79 int 80 iso_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 148 void 149 iso_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 227 struct mbuf * 228 m_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 256 int 257 m_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 277 int 278 m_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 } 356