|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1989, 1993, 1994 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)slcompress.c 8.2 (Berkeley) 4/16/94 ! 59: */ ! 60: ! 61: /* ! 62: * Routines to compress and uncompess tcp packets (for transmission ! 63: * over low speed serial lines. ! 64: * ! 65: * Van Jacobson ([email protected]), Dec 31, 1989: ! 66: * - Initial distribution. ! 67: */ ! 68: ! 69: #include <sys/param.h> ! 70: #include <sys/mbuf.h> ! 71: ! 72: #include <netinet/in.h> ! 73: #include <netinet/in_systm.h> ! 74: #include <netinet/ip.h> ! 75: #include <netinet/tcp.h> ! 76: ! 77: #include <net/slcompress.h> ! 78: ! 79: #ifndef SL_NO_STATS ! 80: #define INCR(counter) ++comp->counter; ! 81: #else ! 82: #define INCR(counter) ! 83: #endif ! 84: ! 85: #define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n)) ! 86: #define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n)) ! 87: #ifndef _KERNEL ! 88: #define ovbcopy bcopy ! 89: #endif ! 90: ! 91: void ! 92: sl_compress_init(comp, max_state) ! 93: struct slcompress *comp; ! 94: int max_state; ! 95: { ! 96: register u_int i; ! 97: register struct cstate *tstate = comp->tstate; ! 98: ! 99: if (max_state == -1) ! 100: max_state = MAX_STATES - 1; ! 101: bzero((char *)comp, sizeof(*comp)); ! 102: for (i = max_state; i > 0; --i) { ! 103: tstate[i].cs_id = i; ! 104: tstate[i].cs_next = &tstate[i - 1]; ! 105: } ! 106: tstate[0].cs_next = &tstate[max_state]; ! 107: tstate[0].cs_id = 0; ! 108: comp->last_cs = &tstate[0]; ! 109: comp->last_recv = 255; ! 110: comp->last_xmit = 255; ! 111: comp->flags = SLF_TOSS; ! 112: } ! 113: ! 114: ! 115: /* ENCODE encodes a number that is known to be non-zero. ENCODEZ ! 116: * checks for zero (since zero has to be encoded in the long, 3 byte ! 117: * form). ! 118: */ ! 119: #define ENCODE(n) { \ ! 120: if ((u_int16_t)(n) >= 256) { \ ! 121: *cp++ = 0; \ ! 122: cp[1] = (n); \ ! 123: cp[0] = (n) >> 8; \ ! 124: cp += 2; \ ! 125: } else { \ ! 126: *cp++ = (n); \ ! 127: } \ ! 128: } ! 129: #define ENCODEZ(n) { \ ! 130: if ((u_int16_t)(n) >= 256 || (u_int16_t)(n) == 0) { \ ! 131: *cp++ = 0; \ ! 132: cp[1] = (n); \ ! 133: cp[0] = (n) >> 8; \ ! 134: cp += 2; \ ! 135: } else { \ ! 136: *cp++ = (n); \ ! 137: } \ ! 138: } ! 139: ! 140: #define DECODEL(f) { \ ! 141: if (*cp == 0) {\ ! 142: (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \ ! 143: cp += 3; \ ! 144: } else { \ ! 145: (f) = htonl(ntohl(f) + (u_int32_t)*cp++); \ ! 146: } \ ! 147: } ! 148: ! 149: #define DECODES(f) { \ ! 150: if (*cp == 0) {\ ! 151: (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \ ! 152: cp += 3; \ ! 153: } else { \ ! 154: (f) = htons(ntohs(f) + (u_int32_t)*cp++); \ ! 155: } \ ! 156: } ! 157: ! 158: #define DECODEU(f) { \ ! 159: if (*cp == 0) {\ ! 160: (f) = htons((cp[1] << 8) | cp[2]); \ ! 161: cp += 3; \ ! 162: } else { \ ! 163: (f) = htons((u_int32_t)*cp++); \ ! 164: } \ ! 165: } ! 166: ! 167: u_int ! 168: sl_compress_tcp(m, ip, comp, compress_cid) ! 169: struct mbuf *m; ! 170: register struct ip *ip; ! 171: struct slcompress *comp; ! 172: int compress_cid; ! 173: { ! 174: register struct cstate *cs = comp->last_cs->cs_next; ! 175: register u_int hlen = ip->ip_hl; ! 176: register struct tcphdr *oth; ! 177: register struct tcphdr *th; ! 178: register u_int deltaS, deltaA; ! 179: register u_int changes = 0; ! 180: u_char new_seq[16]; ! 181: register u_char *cp = new_seq; ! 182: ! 183: /* ! 184: * Bail if this is an IP fragment or if the TCP packet isn't ! 185: * `compressible' (i.e., ACK isn't set or some other control bit is ! 186: * set). (We assume that the caller has already made sure the ! 187: * packet is IP proto TCP). ! 188: */ ! 189: if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40) ! 190: return (TYPE_IP); ! 191: ! 192: th = (struct tcphdr *)&((int32_t *)ip)[hlen]; ! 193: if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) ! 194: return (TYPE_IP); ! 195: /* ! 196: * Packet is compressible -- we're going to send either a ! 197: * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need ! 198: * to locate (or create) the connection state. Special case the ! 199: * most recently used connection since it's most likely to be used ! 200: * again & we don't have to do any reordering if it's used. ! 201: */ ! 202: INCR(sls_packets) ! 203: if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || ! 204: ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || ! 205: *(int32_t *)th != ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl]) { ! 206: /* ! 207: * Wasn't the first -- search for it. ! 208: * ! 209: * States are kept in a circularly linked list with ! 210: * last_cs pointing to the end of the list. The ! 211: * list is kept in lru order by moving a state to the ! 212: * head of the list whenever it is referenced. Since ! 213: * the list is short and, empirically, the connection ! 214: * we want is almost always near the front, we locate ! 215: * states via linear search. If we don't find a state ! 216: * for the datagram, the oldest state is (re-)used. ! 217: */ ! 218: register struct cstate *lcs; ! 219: register struct cstate *lastcs = comp->last_cs; ! 220: ! 221: do { ! 222: lcs = cs; cs = cs->cs_next; ! 223: INCR(sls_searches) ! 224: if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr ! 225: && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr ! 226: && *(int32_t *)th == ! 227: ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl]) ! 228: goto found; ! 229: } while (cs != lastcs); ! 230: ! 231: /* ! 232: * Didn't find it -- re-use oldest cstate. Send an ! 233: * uncompressed packet that tells the other side what ! 234: * connection number we're using for this conversation. ! 235: * Note that since the state list is circular, the oldest ! 236: * state points to the newest and we only need to set ! 237: * last_cs to update the lru linkage. ! 238: */ ! 239: INCR(sls_misses) ! 240: comp->last_cs = lcs; ! 241: hlen += th->th_off; ! 242: hlen <<= 2; ! 243: goto uncompressed; ! 244: ! 245: found: ! 246: /* ! 247: * Found it -- move to the front on the connection list. ! 248: */ ! 249: if (cs == lastcs) ! 250: comp->last_cs = lcs; ! 251: else { ! 252: lcs->cs_next = cs->cs_next; ! 253: cs->cs_next = lastcs->cs_next; ! 254: lastcs->cs_next = cs; ! 255: } ! 256: } ! 257: ! 258: /* ! 259: * Make sure that only what we expect to change changed. The first ! 260: * line of the `if' checks the IP protocol version, header length & ! 261: * type of service. The 2nd line checks the "Don't fragment" bit. ! 262: * The 3rd line checks the time-to-live and protocol (the protocol ! 263: * check is unnecessary but costless). The 4th line checks the TCP ! 264: * header length. The 5th line checks IP options, if any. The 6th ! 265: * line checks TCP options, if any. If any of these things are ! 266: * different between the previous & current datagram, we send the ! 267: * current datagram `uncompressed'. ! 268: */ ! 269: oth = (struct tcphdr *)&((int32_t *)&cs->cs_ip)[hlen]; ! 270: deltaS = hlen; ! 271: hlen += th->th_off; ! 272: hlen <<= 2; ! 273: ! 274: if (((u_int16_t *)ip)[0] != ((u_int16_t *)&cs->cs_ip)[0] || ! 275: ((u_int16_t *)ip)[3] != ((u_int16_t *)&cs->cs_ip)[3] || ! 276: ((u_int16_t *)ip)[4] != ((u_int16_t *)&cs->cs_ip)[4] || ! 277: th->th_off != oth->th_off || ! 278: (deltaS > 5 && ! 279: BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || ! 280: (th->th_off > 5 && ! 281: BCMP(th + 1, oth + 1, (th->th_off - 5) << 2))) ! 282: goto uncompressed; ! 283: ! 284: /* ! 285: * Figure out which of the changing fields changed. The ! 286: * receiver expects changes in the order: urgent, window, ! 287: * ack, seq (the order minimizes the number of temporaries ! 288: * needed in this section of code). ! 289: */ ! 290: if (th->th_flags & TH_URG) { ! 291: deltaS = ntohs(th->th_urp); ! 292: ENCODEZ(deltaS); ! 293: changes |= NEW_U; ! 294: } else if (th->th_urp != oth->th_urp) ! 295: /* argh! URG not set but urp changed -- a sensible ! 296: * implementation should never do this but RFC793 ! 297: * doesn't prohibit the change so we have to deal ! 298: * with it. */ ! 299: goto uncompressed; ! 300: ! 301: if (deltaS = (u_int16_t)(ntohs(th->th_win) - ntohs(oth->th_win))) { ! 302: ENCODE(deltaS); ! 303: changes |= NEW_W; ! 304: } ! 305: ! 306: if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) { ! 307: if (deltaA > 0xffff) ! 308: goto uncompressed; ! 309: ENCODE(deltaA); ! 310: changes |= NEW_A; ! 311: } ! 312: ! 313: if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) { ! 314: if (deltaS > 0xffff) ! 315: goto uncompressed; ! 316: ENCODE(deltaS); ! 317: changes |= NEW_S; ! 318: } ! 319: ! 320: switch(changes) { ! 321: ! 322: case 0: ! 323: /* ! 324: * Nothing changed. If this packet contains data and the ! 325: * last one didn't, this is probably a data packet following ! 326: * an ack (normal on an interactive connection) and we send ! 327: * it compressed. Otherwise it's probably a retransmit, ! 328: * retransmitted ack or window probe. Send it uncompressed ! 329: * in case the other side missed the compressed version. ! 330: */ ! 331: if (ip->ip_len != cs->cs_ip.ip_len && ! 332: ntohs(cs->cs_ip.ip_len) == hlen) ! 333: break; ! 334: ! 335: /* (fall through) */ ! 336: ! 337: case SPECIAL_I: ! 338: case SPECIAL_D: ! 339: /* ! 340: * actual changes match one of our special case encodings -- ! 341: * send packet uncompressed. ! 342: */ ! 343: goto uncompressed; ! 344: ! 345: case NEW_S|NEW_A: ! 346: if (deltaS == deltaA && ! 347: deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { ! 348: /* special case for echoed terminal traffic */ ! 349: changes = SPECIAL_I; ! 350: cp = new_seq; ! 351: } ! 352: break; ! 353: ! 354: case NEW_S: ! 355: if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { ! 356: /* special case for data xfer */ ! 357: changes = SPECIAL_D; ! 358: cp = new_seq; ! 359: } ! 360: break; ! 361: } ! 362: ! 363: deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); ! 364: if (deltaS != 1) { ! 365: ENCODEZ(deltaS); ! 366: changes |= NEW_I; ! 367: } ! 368: if (th->th_flags & TH_PUSH) ! 369: changes |= TCP_PUSH_BIT; ! 370: /* ! 371: * Grab the cksum before we overwrite it below. Then update our ! 372: * state with this packet's header. ! 373: */ ! 374: deltaA = ntohs(th->th_sum); ! 375: BCOPY(ip, &cs->cs_ip, hlen); ! 376: ! 377: /* ! 378: * We want to use the original packet as our compressed packet. ! 379: * (cp - new_seq) is the number of bytes we need for compressed ! 380: * sequence numbers. In addition we need one byte for the change ! 381: * mask, one for the connection id and two for the tcp checksum. ! 382: * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how ! 383: * many bytes of the original packet to toss so subtract the two to ! 384: * get the new packet size. ! 385: */ ! 386: deltaS = cp - new_seq; ! 387: cp = (u_char *)ip; ! 388: if (compress_cid == 0 || comp->last_xmit != cs->cs_id) { ! 389: comp->last_xmit = cs->cs_id; ! 390: hlen -= deltaS + 4; ! 391: cp += hlen; ! 392: *cp++ = changes | NEW_C; ! 393: *cp++ = cs->cs_id; ! 394: } else { ! 395: hlen -= deltaS + 3; ! 396: cp += hlen; ! 397: *cp++ = changes; ! 398: } ! 399: m->m_len -= hlen; ! 400: m->m_data += hlen; ! 401: *cp++ = deltaA >> 8; ! 402: *cp++ = deltaA; ! 403: BCOPY(new_seq, cp, deltaS); ! 404: INCR(sls_compressed) ! 405: return (TYPE_COMPRESSED_TCP); ! 406: ! 407: /* ! 408: * Update connection state cs & send uncompressed packet ('uncompressed' ! 409: * means a regular ip/tcp packet but with the 'conversation id' we hope ! 410: * to use on future compressed packets in the protocol field). ! 411: */ ! 412: uncompressed: ! 413: BCOPY(ip, &cs->cs_ip, hlen); ! 414: ip->ip_p = cs->cs_id; ! 415: comp->last_xmit = cs->cs_id; ! 416: return (TYPE_UNCOMPRESSED_TCP); ! 417: } ! 418: ! 419: ! 420: int ! 421: sl_uncompress_tcp(bufp, len, type, comp) ! 422: u_char **bufp; ! 423: int len; ! 424: u_int type; ! 425: struct slcompress *comp; ! 426: { ! 427: ! 428: return sl_uncompress_tcp_part(bufp, len, len, type, comp); ! 429: } ! 430: ! 431: /* ! 432: * Uncompress a packet of total length total_len. The first buflen ! 433: * bytes are at *bufp; this must include the entire (compressed or ! 434: * uncompressed) TCP/IP header. In addition, there must be enough ! 435: * clear space before *bufp to build a full-length TCP/IP header. ! 436: */ ! 437: int ! 438: sl_uncompress_tcp_part(bufp, buflen, total_len, type, comp) ! 439: u_char **bufp; ! 440: int buflen, total_len; ! 441: u_int type; ! 442: struct slcompress *comp; ! 443: { ! 444: register u_char *cp; ! 445: register u_int hlen, changes; ! 446: register struct tcphdr *th; ! 447: register struct cstate *cs; ! 448: register struct ip *ip; ! 449: ! 450: switch (type) { ! 451: ! 452: case TYPE_UNCOMPRESSED_TCP: ! 453: ip = (struct ip *) *bufp; ! 454: if (ip->ip_p >= MAX_STATES) ! 455: goto bad; ! 456: cs = &comp->rstate[comp->last_recv = ip->ip_p]; ! 457: comp->flags &=~ SLF_TOSS; ! 458: ip->ip_p = IPPROTO_TCP; ! 459: hlen = ip->ip_hl; ! 460: hlen += ((struct tcphdr *)&((int32_t *)ip)[hlen])->th_off; ! 461: hlen <<= 2; ! 462: BCOPY(ip, &cs->cs_ip, hlen); ! 463: cs->cs_ip.ip_sum = 0; ! 464: cs->cs_hlen = hlen; ! 465: INCR(sls_uncompressedin) ! 466: return (total_len); ! 467: ! 468: default: ! 469: goto bad; ! 470: ! 471: case TYPE_COMPRESSED_TCP: ! 472: break; ! 473: } ! 474: /* We've got a compressed packet. */ ! 475: INCR(sls_compressedin) ! 476: cp = *bufp; ! 477: changes = *cp++; ! 478: if (changes & NEW_C) { ! 479: /* Make sure the state index is in range, then grab the state. ! 480: * If we have a good state index, clear the 'discard' flag. */ ! 481: if (*cp >= MAX_STATES) ! 482: goto bad; ! 483: ! 484: comp->flags &=~ SLF_TOSS; ! 485: comp->last_recv = *cp++; ! 486: } else { ! 487: /* this packet has an implicit state index. If we've ! 488: * had a line error since the last time we got an ! 489: * explicit state index, we have to toss the packet. */ ! 490: if (comp->flags & SLF_TOSS) { ! 491: INCR(sls_tossed) ! 492: return (0); ! 493: } ! 494: } ! 495: cs = &comp->rstate[comp->last_recv]; ! 496: hlen = cs->cs_ip.ip_hl << 2; ! 497: th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; ! 498: th->th_sum = htons((*cp << 8) | cp[1]); ! 499: cp += 2; ! 500: if (changes & TCP_PUSH_BIT) ! 501: th->th_flags |= TH_PUSH; ! 502: else ! 503: th->th_flags &=~ TH_PUSH; ! 504: ! 505: switch (changes & SPECIALS_MASK) { ! 506: case SPECIAL_I: ! 507: { ! 508: register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; ! 509: th->th_ack = htonl(ntohl(th->th_ack) + i); ! 510: th->th_seq = htonl(ntohl(th->th_seq) + i); ! 511: } ! 512: break; ! 513: ! 514: case SPECIAL_D: ! 515: th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) ! 516: - cs->cs_hlen); ! 517: break; ! 518: ! 519: default: ! 520: if (changes & NEW_U) { ! 521: th->th_flags |= TH_URG; ! 522: DECODEU(th->th_urp) ! 523: } else ! 524: th->th_flags &=~ TH_URG; ! 525: if (changes & NEW_W) ! 526: DECODES(th->th_win) ! 527: if (changes & NEW_A) ! 528: DECODEL(th->th_ack) ! 529: if (changes & NEW_S) ! 530: DECODEL(th->th_seq) ! 531: break; ! 532: } ! 533: if (changes & NEW_I) { ! 534: DECODES(cs->cs_ip.ip_id) ! 535: } else ! 536: cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1); ! 537: ! 538: /* ! 539: * At this point, cp points to the first byte of data in the ! 540: * packet. If we're not aligned on a 4-byte boundary, copy the ! 541: * data down so the ip & tcp headers will be aligned. Then back up ! 542: * cp by the tcp/ip header length to make room for the reconstructed ! 543: * header (we assume the packet we were handed has enough space to ! 544: * prepend 128 bytes of header). Adjust the length to account for ! 545: * the new header & fill in the IP total length. ! 546: */ ! 547: buflen -= (cp - *bufp); ! 548: total_len -= (cp - *bufp); ! 549: if (buflen < 0) ! 550: /* we must have dropped some characters (crc should detect ! 551: * this but the old slip framing won't) */ ! 552: goto bad; ! 553: ! 554: if ((long)cp & 3) { ! 555: if (buflen > 0) ! 556: (void) ovbcopy(cp, (caddr_t)((long)cp &~ 3), buflen); ! 557: cp = (u_char *)((long)cp &~ 3); ! 558: } ! 559: cp -= cs->cs_hlen; ! 560: total_len += cs->cs_hlen; ! 561: cs->cs_ip.ip_len = htons(total_len); ! 562: BCOPY(&cs->cs_ip, cp, cs->cs_hlen); ! 563: *bufp = cp; ! 564: ! 565: /* recompute the ip header checksum */ ! 566: { ! 567: register u_int16_t *bp = (u_int16_t *)cp; ! 568: for (changes = 0; hlen > 0; hlen -= 2) ! 569: changes += *bp++; ! 570: changes = (changes & 0xffff) + (changes >> 16); ! 571: changes = (changes & 0xffff) + (changes >> 16); ! 572: ((struct ip *)cp)->ip_sum = ~ changes; ! 573: } ! 574: return (total_len); ! 575: bad: ! 576: comp->flags |= SLF_TOSS; ! 577: INCR(sls_errorin) ! 578: return (0); ! 579: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.