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