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 * @(#)iso_chksum.c 7.4 (Berkeley) 09/26/89 * 31 * 32 * ISO CHECKSUM 33 * 34 * The checksum generation and check routines are here. 35 * The checksum is 2 bytes such that the sum of all the bytes b(i) == 0 36 * and the sum of i * b(i) == 0. 37 * The whole thing is complicated by the fact that the data are in mbuf 38 * chains. 39 * Furthermore, there is the possibility of wraparound in the running 40 * sums after adding up 4102 octets. In order to avoid doing a mod 41 * operation after EACH add, we have restricted this implementation to 42 * negotiating a maximum of 4096-octets per TPDU (for the transport layer). 43 * The routine iso_check_csum doesn't need to know where the checksum 44 * octets are. 45 * The routine iso_gen_csum takes a pointer to an mbuf chain (logically 46 * a chunk of data), an offset into the chunk at which the 2 octets are to 47 * be stuffed, and the length of the chunk. The 2 octets have to be 48 * logically adjacent, but may be physically located in separate mbufs. 49 */ 50 51 #ifdef ISO 52 #ifndef lint 53 static char *rcsid = "$Header: iso_chksum.c,v 4.7 88/07/29 15:31:26 nhall Exp $"; 54 #endif 55 56 #include "argo_debug.h" 57 #include "param.h" 58 #include "mbuf.h" 59 #endif ISO 60 61 #ifndef MNULL 62 #define MNULL (struct mbuf *)0 63 #endif MNULL 64 65 /* 66 * FUNCTION: iso_check_csum 67 * 68 * PURPOSE: To check the checksum of the packet in the mbuf chain (m). 69 * The total length of the packet is (len). 70 * Called from tp_input() and clnp_intr() 71 * 72 * RETURNS: TRUE (something non-zero) if there is a checksum error, 73 * FALSE if there was NO checksum error. 74 * 75 * SIDE EFFECTS: none 76 * 77 * NOTES: It might be possible to gain something by optimizing 78 * this routine (unrolling loops, etc). But it is such 79 * a horrible thing to fiddle with anyway, it probably 80 * isn't worth it. 81 */ 82 int 83 iso_check_csum(m, len) 84 struct mbuf *m; 85 int len; 86 { 87 register u_char *p = mtod(m, u_char *); 88 register u_long c0=0, c1=0; 89 register int i=0; 90 int cum = 0; /* cumulative length */ 91 int l; 92 93 l = len; 94 len = MIN(m->m_len, len); 95 i = 0; 96 97 IFDEBUG(D_CHKSUM) 98 printf("iso_check_csum: m x%x, l x%x, m->m_len x%x\n", m, l, m->m_len); 99 ENDDEBUG 100 101 while( i<l ) { 102 cum += len; 103 while (i<cum) { 104 c0 = c0 + *(p++); 105 c1 += c0; 106 i++; 107 } 108 if(i < l) { 109 m = m->m_next; 110 IFDEBUG(D_CHKSUM) 111 printf("iso_check_csum: new mbuf\n"); 112 if(l-i < m->m_len) 113 printf( 114 "bad mbuf chain in check csum l 0x%x i 0x%x m_data 0x%x", 115 l,i,m->m_data); 116 ENDDEBUG 117 ASSERT( m != MNULL); 118 len = MIN( m->m_len, l-i); 119 p = mtod(m, u_char *); 120 } 121 } 122 if ( ((int)c0 % 255) || ((int)c1 % 255) ) { 123 IFDEBUG(D_CHKSUM) 124 printf("BAD iso_check_csum l 0x%x cum 0x%x len 0x%x, i 0x%x", 125 l, cum, len, i); 126 ENDDEBUG 127 return ((int)c0 % 255)<<8 | ((int)c1 % 255); 128 } 129 return 0; 130 } 131 132 /* 133 * FUNCTION: iso_gen_csum 134 * 135 * PURPOSE: To generate the checksum of the packet in the mbuf chain (m). 136 * The first of the 2 (logically) adjacent checksum bytes 137 * (x and y) go at offset (n). 138 * (n) is an offset relative to the beginning of the data, 139 * not the beginning of the mbuf. 140 * (l) is the length of the total mbuf chain's data. 141 * Called from tp_emit(), tp_error_emit() 142 * clnp_emit_er(), clnp_forward(), clnp_output(). 143 * 144 * RETURNS: Rien 145 * 146 * SIDE EFFECTS: Puts the 2 checksum bytes into the packet. 147 * 148 * NOTES: Ditto the note for iso_check_csum(). 149 */ 150 151 void 152 iso_gen_csum(m,n,l) 153 struct mbuf *m; 154 int n; /* offset of 2 checksum bytes */ 155 int l; 156 { 157 register u_char *p = mtod(m, u_char *); 158 register int c0=0, c1=0; 159 register int i=0; 160 int loc = n++, len=0; /* n is position, loc is offset */ 161 u_char *xloc; 162 u_char *yloc; 163 int cum=0; /* cum == cumulative length */ 164 165 IFDEBUG(D_CHKSUM) 166 printf("enter gen csum m 0x%x n 0x%x l 0x%x\n",m, n-1 ,l ); 167 ENDDEBUG 168 169 while(i < l) { 170 len = MIN(m->m_len, CLBYTES); 171 /* RAH: don't cksum more than l bytes */ 172 len = MIN(len, l - i); 173 174 cum +=len; 175 p = mtod(m, u_char *); 176 177 if(loc>=0) { 178 if (loc < len) { 179 xloc = loc + mtod(m, u_char *); 180 IFDEBUG(D_CHKSUM) 181 printf("1: zeroing xloc 0x%x loc 0x%x\n",xloc, loc ); 182 ENDDEBUG 183 *xloc = (u_char)0; 184 if (loc+1 < len) { 185 /* both xloc and yloc are in same mbuf */ 186 yloc = 1 + xloc; 187 IFDEBUG(D_CHKSUM) 188 printf("2: zeroing yloc 0x%x loc 0x%x\n",yloc, loc ); 189 ENDDEBUG 190 *yloc = (u_char)0; 191 } else { 192 /* crosses boundary of mbufs */ 193 yloc = mtod(m->m_next, u_char *); 194 IFDEBUG(D_CHKSUM) 195 printf("3: zeroing yloc 0x%x \n",yloc ); 196 ENDDEBUG 197 *yloc = (u_char)0; 198 } 199 } 200 loc -= len; 201 } 202 203 while(i < cum) { 204 c0 = (c0 + *p); 205 c1 += c0 ; 206 i++; 207 p++; 208 } 209 m = m->m_next; 210 } 211 IFDEBUG(D_CHKSUM) 212 printf("gen csum final xloc 0x%x yloc 0x%x\n",xloc, yloc ); 213 ENDDEBUG 214 215 c1 = (((c0 * (l-n))-c1)%255) ; 216 *xloc = (u_char) ((c1 < 0)? c1+255 : c1); 217 218 c1 = (-(int)(c1+c0))%255; 219 *yloc = (u_char) (c1 < 0? c1 + 255 : c1); 220 221 IFDEBUG(D_CHKSUM) 222 printf("gen csum end \n"); 223 ENDDEBUG 224 } 225 226 struct mbuf * 227 m_append(head, m) 228 struct mbuf *head, *m; 229 { 230 register struct mbuf *n; 231 232 if (m == 0) 233 return head; 234 if (head == 0) 235 return m; 236 n = head; 237 while (n->m_next) 238 n = n->m_next; 239 n->m_next = m; 240 return head; 241 } 242 /* 243 * FUNCTION: m_datalen 244 * 245 * PURPOSE: returns length of the mbuf chain. 246 * used all over the iso code. 247 * 248 * RETURNS: integer 249 * 250 * SIDE EFFECTS: none 251 * 252 * NOTES: 253 */ 254 255 int 256 m_datalen (morig) 257 struct mbuf *morig; 258 { 259 int s = splimp(); 260 register struct mbuf *n=morig; 261 register int datalen = 0; 262 263 if( morig == (struct mbuf *)0) 264 return 0; 265 for(;;) { 266 datalen += n->m_len; 267 if (n->m_next == (struct mbuf *)0 ) { 268 break; 269 } 270 n = n->m_next; 271 } 272 splx(s); 273 return datalen; 274 } 275 276 int 277 m_compress(in, out) 278 register struct mbuf *in, **out; 279 { 280 register int datalen = 0; 281 int s = splimp(); 282 283 if( in->m_next == MNULL ) { 284 *out = in; 285 IFDEBUG(D_REQUEST) 286 printf("m_compress returning 0x%x: A\n", in->m_len); 287 ENDDEBUG 288 splx(s); 289 return in->m_len; 290 } 291 MGET((*out), M_DONTWAIT, MT_DATA); 292 if((*out) == MNULL) { 293 *out = in; 294 IFDEBUG(D_REQUEST) 295 printf("m_compress returning -1: B\n"); 296 ENDDEBUG 297 splx(s); 298 return -1; 299 } 300 (*out)->m_len = 0; 301 (*out)->m_act = MNULL; 302 303 while (in) { 304 IFDEBUG(D_REQUEST) 305 printf("m_compress in 0x%x *out 0x%x\n", in, *out); 306 printf("m_compress in: len 0x%x, off 0x%x\n", in->m_len, in->m_data); 307 printf("m_compress *out: len 0x%x, off 0x%x\n", (*out)->m_len, 308 (*out)->m_data); 309 ENDDEBUG 310 if (in->m_flags & M_EXT) { 311 ASSERT(in->m_len == 0); 312 } 313 if ( in->m_len == 0) { 314 in = in->m_next; 315 continue; 316 } 317 if (((*out)->m_flags & M_EXT) == 0) { 318 int len; 319 320 len = M_TRAILINGSPACE(*out); 321 len = MIN(len, in->m_len); 322 datalen += len; 323 324 IFDEBUG(D_REQUEST) 325 printf("m_compress copying len %d\n", len); 326 ENDDEBUG 327 bcopy(mtod(in, caddr_t), mtod((*out), caddr_t) + (*out)->m_len, 328 (unsigned)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