1*39948Ssam /* slcompress.c 7.5 90/01/20 */ 238361Ssam /* 338361Ssam * Routines to compress and uncompess tcp packets (for transmission 438361Ssam * over low speed serial lines. 538361Ssam * 6*39948Ssam * Copyright (c) 1989 Regents of the University of California. 738361Ssam * All rights reserved. 8*39948Ssam * 9*39948Ssam * Redistribution and use in source and binary forms are permitted 10*39948Ssam * provided that the above copyright notice and this paragraph are 11*39948Ssam * duplicated in all such forms and that any documentation, 12*39948Ssam * advertising materials, and other materials related to such 13*39948Ssam * distribution and use acknowledge that the software was developed 14*39948Ssam * by the University of California, Berkeley. The name of the 15*39948Ssam * University may not be used to endorse or promote products derived 16*39948Ssam * from this software without specific prior written permission. 17*39948Ssam * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 18*39948Ssam * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 19*39948Ssam * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20*39948Ssam * 21*39948Ssam * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: 22*39948Ssam * - Initial distribution. 2338361Ssam */ 2438361Ssam #ifndef lint 25*39948Ssam static char rcsid[] = "$Header: slcompress.c,v 1.19 89/12/31 08:52:59 van Exp $"; 2638361Ssam #endif 2738361Ssam 2838361Ssam #include <sys/types.h> 2938361Ssam #include <sys/param.h> 3038361Ssam #include <sys/mbuf.h> 3138361Ssam #include <netinet/in.h> 3238361Ssam #include <netinet/in_systm.h> 3338361Ssam #include <netinet/ip.h> 3438361Ssam #include <netinet/tcp.h> 3538361Ssam 3638361Ssam #include "slcompress.h" 3738361Ssam 38*39948Ssam #ifndef SL_NO_STATS 3938374Skarels #define INCR(counter) ++comp->counter; 4038374Skarels #else 4138374Skarels #define INCR(counter) 4238374Skarels #endif 4338361Ssam 4438361Ssam #define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n)) 4538361Ssam #define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n)) 46*39948Ssam #ifndef KERNEL 47*39948Ssam #define ovbcopy bcopy 48*39948Ssam #endif 4938361Ssam 5038361Ssam 5138361Ssam void 5238361Ssam sl_compress_init(comp) 5338361Ssam struct slcompress *comp; 5438361Ssam { 5538361Ssam register u_int i; 5638361Ssam register struct cstate *tstate = comp->tstate; 5738361Ssam 5838361Ssam bzero((char *)comp, sizeof(*comp)); 5938361Ssam for (i = MAX_STATES - 1; i > 0; --i) { 6038361Ssam tstate[i].cs_id = i; 6138361Ssam tstate[i].cs_next = &tstate[i - 1]; 6238361Ssam } 6338361Ssam tstate[0].cs_next = &tstate[MAX_STATES - 1]; 6438361Ssam tstate[0].cs_id = 0; 6538361Ssam comp->last_cs = &tstate[0]; 6638361Ssam comp->last_recv = 255; 6738361Ssam comp->last_xmit = 255; 6838361Ssam } 6938361Ssam 7038361Ssam 7138361Ssam /* ENCODE encodes a number that is known to be non-zero. ENCODEZ 7238361Ssam * checks for zero (since zero has to be encoded in the long, 3 byte 7338361Ssam * form). 7438361Ssam */ 7538361Ssam #define ENCODE(n) { \ 7638361Ssam if ((u_short)(n) >= 256) { \ 7738361Ssam *cp++ = 0; \ 7838361Ssam cp[1] = (n); \ 7938361Ssam cp[0] = (n) >> 8; \ 8038361Ssam cp += 2; \ 8138361Ssam } else { \ 8238361Ssam *cp++ = (n); \ 8338361Ssam } \ 8438361Ssam } 8538361Ssam #define ENCODEZ(n) { \ 8638361Ssam if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ 8738361Ssam *cp++ = 0; \ 8838361Ssam cp[1] = (n); \ 8938361Ssam cp[0] = (n) >> 8; \ 9038361Ssam cp += 2; \ 9138361Ssam } else { \ 9238361Ssam *cp++ = (n); \ 9338361Ssam } \ 9438361Ssam } 9538361Ssam 9638361Ssam #define DECODEL(f) { \ 9738361Ssam if (*cp == 0) {\ 9838361Ssam (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \ 9938361Ssam cp += 3; \ 10038361Ssam } else { \ 10138361Ssam (f) = htonl(ntohl(f) + (u_long)*cp++); \ 10238361Ssam } \ 10338361Ssam } 10438361Ssam 10538361Ssam #define DECODES(f) { \ 10638361Ssam if (*cp == 0) {\ 10738361Ssam (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \ 10838361Ssam cp += 3; \ 10938361Ssam } else { \ 11038361Ssam (f) = htons(ntohs(f) + (u_long)*cp++); \ 11138361Ssam } \ 11238361Ssam } 11338361Ssam 114*39948Ssam #define DECODEU(f) { \ 115*39948Ssam if (*cp == 0) {\ 116*39948Ssam (f) = htons((cp[1] << 8) | cp[2]); \ 117*39948Ssam cp += 3; \ 118*39948Ssam } else { \ 119*39948Ssam (f) = htons((u_long)*cp++); \ 120*39948Ssam } \ 121*39948Ssam } 12238361Ssam 123*39948Ssam 12438361Ssam u_char 125*39948Ssam sl_compress_tcp(m, ip, comp, compress_cid) 12638361Ssam struct mbuf *m; 12738361Ssam register struct ip *ip; 12838361Ssam struct slcompress *comp; 129*39948Ssam int compress_cid; 13038361Ssam { 13138361Ssam register struct cstate *cs = comp->last_cs->cs_next; 13238361Ssam register u_int hlen = ip->ip_hl; 13338361Ssam register struct tcphdr *oth; 13438361Ssam register struct tcphdr *th; 13538361Ssam register u_int deltaS, deltaA; 13638361Ssam register u_int changes = 0; 13738361Ssam u_char new_seq[16]; 13838361Ssam register u_char *cp = new_seq; 13938361Ssam 14038361Ssam /* 141*39948Ssam * Bail if this is an IP fragment or if the TCP packet isn't 142*39948Ssam * `compressible' (i.e., ACK isn't set or some other control bit is 143*39948Ssam * set). (We assume that the caller has already made sure the 144*39948Ssam * packet is IP proto TCP). 14538361Ssam */ 146*39948Ssam if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40) 14738361Ssam return (TYPE_IP); 14838361Ssam 14938361Ssam th = (struct tcphdr *)&((int *)ip)[hlen]; 15038361Ssam if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) 15138361Ssam return (TYPE_IP); 152*39948Ssam /* 153*39948Ssam * Packet is compressible -- we're going to send either a 154*39948Ssam * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need 155*39948Ssam * to locate (or create) the connection state. Special case the 156*39948Ssam * most recently used connection since it's most likely to be used 157*39948Ssam * again & we don't have to do any reordering if it's used. 158*39948Ssam */ 15938374Skarels INCR(sls_packets) 16038374Skarels if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || 16138374Skarels ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || 16238374Skarels *(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) { 16338361Ssam /* 16438361Ssam * Wasn't the first -- search for it. 16538361Ssam * 16638361Ssam * States are kept in a circularly linked list with 167*39948Ssam * last_cs pointing to the end of the list. The 16838361Ssam * list is kept in lru order by moving a state to the 16938361Ssam * head of the list whenever it is referenced. Since 17038361Ssam * the list is short and, empirically, the connection 17138361Ssam * we want is almost always near the front, we locate 17238361Ssam * states via linear search. If we don't find a state 173*39948Ssam * for the datagram, the oldest state is (re-)used. 17438361Ssam */ 17538361Ssam register struct cstate *lcs; 176*39948Ssam register struct cstate *lastcs = comp->last_cs; 17738361Ssam 17838361Ssam do { 17938361Ssam lcs = cs; cs = cs->cs_next; 18038374Skarels INCR(sls_searches) 181*39948Ssam if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr 182*39948Ssam && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr 183*39948Ssam && *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) 18438361Ssam goto found; 185*39948Ssam } while (cs != lastcs); 18638361Ssam 18738361Ssam /* 188*39948Ssam * Didn't find it -- re-use oldest cstate. Send an 189*39948Ssam * uncompressed packet that tells the other side what 190*39948Ssam * connection number we're using for this conversation. 191*39948Ssam * Note that since the state list is circular, the oldest 192*39948Ssam * state points to the newest and we only need to set 193*39948Ssam * last_cs to update the lru linkage. 19438361Ssam */ 195*39948Ssam INCR(sls_misses) 19638361Ssam comp->last_cs = lcs; 19738361Ssam hlen += th->th_off; 19838361Ssam hlen <<= 2; 19938361Ssam goto uncompressed; 20038361Ssam 20138361Ssam found: 20238361Ssam /* 20338361Ssam * Found it -- move to the front on the connection list. 20438361Ssam */ 205*39948Ssam if (cs == lastcs) 20638361Ssam comp->last_cs = lcs; 20738361Ssam else { 20838361Ssam lcs->cs_next = cs->cs_next; 209*39948Ssam cs->cs_next = lastcs->cs_next; 210*39948Ssam lastcs->cs_next = cs; 21138361Ssam } 21238361Ssam } 21338361Ssam 21438361Ssam /* 215*39948Ssam * Make sure that only what we expect to change changed. The first 216*39948Ssam * line of the `if' checks the IP protocol version, header length & 217*39948Ssam * type of service. The 2nd line checks the "Don't fragment" bit. 218*39948Ssam * The 3rd line checks the time-to-live and protocol (the protocol 219*39948Ssam * check is unnecessary but costless). The 4th line checks the TCP 220*39948Ssam * header length. The 5th line checks IP options, if any. The 6th 221*39948Ssam * line checks TCP options, if any. If any of these things are 222*39948Ssam * different between the previous & current datagram, we send the 223*39948Ssam * current datagram `uncompressed'. 22438361Ssam */ 22538361Ssam oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen]; 22638361Ssam deltaS = hlen; 22738361Ssam hlen += th->th_off; 22838361Ssam hlen <<= 2; 22938361Ssam 23038361Ssam if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] || 231*39948Ssam ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] || 23238361Ssam ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] || 23338361Ssam th->th_off != oth->th_off || 23438361Ssam (deltaS > 5 && 23538361Ssam BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || 23638361Ssam (th->th_off > 5 && 23738361Ssam BCMP(th + 1, oth + 1, (th->th_off - 5) << 2))) 23838361Ssam goto uncompressed; 23938361Ssam 24038361Ssam /* 24138361Ssam * Figure out which of the changing fields changed. The 24238361Ssam * receiver expects changes in the order: urgent, window, 24338361Ssam * ack, seq (the order minimizes the number of temporaries 24438361Ssam * needed in this section of code). 24538361Ssam */ 24638361Ssam if (th->th_flags & TH_URG) { 24738361Ssam deltaS = ntohs(th->th_urp); 24838361Ssam ENCODEZ(deltaS); 24938361Ssam changes |= NEW_U; 25038361Ssam } else if (th->th_urp != oth->th_urp) 25138361Ssam /* argh! URG not set but urp changed -- a sensible 25238361Ssam * implementation should never do this but RFC793 25338361Ssam * doesn't prohibit the change so we have to deal 254*39948Ssam * with it. */ 25538361Ssam goto uncompressed; 25638361Ssam 25738361Ssam if (deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) { 25838361Ssam ENCODE(deltaS); 25938361Ssam changes |= NEW_W; 26038361Ssam } 26138361Ssam 26238361Ssam if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) { 26338361Ssam if (deltaA > 0xffff) 26438361Ssam goto uncompressed; 26538361Ssam ENCODE(deltaA); 26638361Ssam changes |= NEW_A; 26738361Ssam } 26838361Ssam 26938361Ssam if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) { 27038361Ssam if (deltaS > 0xffff) 27138361Ssam goto uncompressed; 27238361Ssam ENCODE(deltaS); 27338361Ssam changes |= NEW_S; 27438361Ssam } 27538361Ssam 27638361Ssam switch(changes) { 27738361Ssam 27838361Ssam case 0: 27938361Ssam /* 280*39948Ssam * Nothing changed. If this packet contains data and the 281*39948Ssam * last one didn't, this is probably a data packet following 282*39948Ssam * an ack (normal on an interactive connection) and we send 283*39948Ssam * it compressed. Otherwise it's probably a retransmit, 284*39948Ssam * retransmitted ack or window probe. Send it uncompressed 285*39948Ssam * in case the other side missed the compressed version. 28638361Ssam */ 287*39948Ssam if (ip->ip_len != cs->cs_ip.ip_len && 288*39948Ssam ntohs(cs->cs_ip.ip_len) == hlen) 289*39948Ssam break; 29038361Ssam 291*39948Ssam /* (fall through) */ 292*39948Ssam 29338361Ssam case SPECIAL_I: 29438361Ssam case SPECIAL_D: 29538361Ssam /* 29638361Ssam * actual changes match one of our special case encodings -- 29738361Ssam * send packet uncompressed. 29838361Ssam */ 29938361Ssam goto uncompressed; 30038361Ssam 30138361Ssam case NEW_S|NEW_A: 30238361Ssam if (deltaS == deltaA && 30338361Ssam deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { 30438361Ssam /* special case for echoed terminal traffic */ 30538361Ssam changes = SPECIAL_I; 30638361Ssam cp = new_seq; 30738361Ssam } 30838361Ssam break; 30938361Ssam 31038361Ssam case NEW_S: 31138361Ssam if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { 31238361Ssam /* special case for data xfer */ 31338361Ssam changes = SPECIAL_D; 31438361Ssam cp = new_seq; 31538361Ssam } 31638361Ssam break; 31738361Ssam } 31838361Ssam 31938361Ssam deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); 32038361Ssam if (deltaS != 1) { 32138361Ssam ENCODEZ(deltaS); 32238361Ssam changes |= NEW_I; 32338361Ssam } 32438361Ssam if (th->th_flags & TH_PUSH) 32538361Ssam changes |= TCP_PUSH_BIT; 32638361Ssam /* 32738361Ssam * Grab the cksum before we overwrite it below. Then update our 32838361Ssam * state with this packet's header. 32938361Ssam */ 33038361Ssam deltaA = ntohs(th->th_sum); 33138361Ssam BCOPY(ip, &cs->cs_ip, hlen); 33238361Ssam 33338361Ssam /* 33438361Ssam * We want to use the original packet as our compressed packet. 33538361Ssam * (cp - new_seq) is the number of bytes we need for compressed 33638361Ssam * sequence numbers. In addition we need one byte for the change 33738361Ssam * mask, one for the connection id and two for the tcp checksum. 33838361Ssam * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how 33938361Ssam * many bytes of the original packet to toss so subtract the two to 34038361Ssam * get the new packet size. 34138361Ssam */ 34238361Ssam deltaS = cp - new_seq; 34338361Ssam cp = (u_char *)ip; 344*39948Ssam if (compress_cid == 0 || comp->last_xmit != cs->cs_id) { 34538361Ssam comp->last_xmit = cs->cs_id; 34638361Ssam hlen -= deltaS + 4; 34738374Skarels cp += hlen; 34838374Skarels *cp++ = changes | NEW_C; 34938361Ssam *cp++ = cs->cs_id; 35038361Ssam } else { 35138361Ssam hlen -= deltaS + 3; 35238374Skarels cp += hlen; 35338374Skarels *cp++ = changes; 35438361Ssam } 355*39948Ssam m->m_len -= hlen; 356*39948Ssam m->m_data += hlen; 35738361Ssam *cp++ = deltaA >> 8; 35838361Ssam *cp++ = deltaA; 35938361Ssam BCOPY(new_seq, cp, deltaS); 36038374Skarels INCR(sls_compressed) 36138361Ssam return (TYPE_COMPRESSED_TCP); 36238361Ssam 36338361Ssam /* 36438361Ssam * Update connection state cs & send uncompressed packet ('uncompressed' 36538361Ssam * means a regular ip/tcp packet but with the 'conversation id' we hope 36638361Ssam * to use on future compressed packets in the protocol field). 36738361Ssam */ 36838361Ssam uncompressed: 36938361Ssam BCOPY(ip, &cs->cs_ip, hlen); 37038361Ssam ip->ip_p = cs->cs_id; 37138361Ssam comp->last_xmit = cs->cs_id; 37238361Ssam return (TYPE_UNCOMPRESSED_TCP); 37338361Ssam } 37438361Ssam 37538361Ssam 37638374Skarels int 37738374Skarels sl_uncompress_tcp(bufp, len, type, comp) 37838374Skarels u_char **bufp; 37938374Skarels int len; 38038374Skarels u_int type; 38138361Ssam struct slcompress *comp; 38238361Ssam { 38338361Ssam register u_char *cp; 38438361Ssam register u_int hlen, changes; 38538361Ssam register struct tcphdr *th; 38638361Ssam register struct cstate *cs; 38738361Ssam register struct ip *ip; 38838361Ssam 38938361Ssam switch (type) { 39038361Ssam 39138361Ssam case TYPE_UNCOMPRESSED_TCP: 39238374Skarels ip = (struct ip *) *bufp; 393*39948Ssam if (ip->ip_p >= MAX_STATES) 394*39948Ssam goto bad; 39538361Ssam cs = &comp->rstate[comp->last_recv = ip->ip_p]; 39638361Ssam comp->flags &=~ SLF_TOSS; 39738361Ssam ip->ip_p = IPPROTO_TCP; 39838361Ssam hlen = ip->ip_hl; 39938361Ssam hlen += ((struct tcphdr *)&((int *)ip)[hlen])->th_off; 40038361Ssam hlen <<= 2; 40138361Ssam BCOPY(ip, &cs->cs_ip, hlen); 40238361Ssam cs->cs_ip.ip_sum = 0; 40338361Ssam cs->cs_hlen = hlen; 40438374Skarels INCR(sls_uncompressedin) 40538374Skarels return (len); 40638361Ssam 40738374Skarels default: 408*39948Ssam goto bad; 40938361Ssam 41038361Ssam case TYPE_COMPRESSED_TCP: 41138361Ssam break; 41238361Ssam } 41338361Ssam /* We've got a compressed packet. */ 41438374Skarels INCR(sls_compressedin) 41538374Skarels cp = *bufp; 41638361Ssam changes = *cp++; 41738361Ssam if (changes & NEW_C) { 41838361Ssam /* Make sure the state index is in range, then grab the state. 41938361Ssam * If we have a good state index, clear the 'discard' flag. */ 420*39948Ssam if (*cp >= MAX_STATES) 421*39948Ssam goto bad; 422*39948Ssam 42338361Ssam comp->flags &=~ SLF_TOSS; 42438361Ssam comp->last_recv = *cp++; 42538361Ssam } else { 42638361Ssam /* this packet has an implicit state index. If we've 42738361Ssam * had a line error since the last time we got an 42838361Ssam * explicit state index, we have to toss the packet. */ 42938374Skarels if (comp->flags & SLF_TOSS) { 43038374Skarels INCR(sls_tossed) 43138374Skarels return (0); 43238374Skarels } 43338361Ssam } 43438361Ssam cs = &comp->rstate[comp->last_recv]; 43538361Ssam hlen = cs->cs_ip.ip_hl << 2; 43638361Ssam th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; 43738361Ssam th->th_sum = htons((*cp << 8) | cp[1]); 43838361Ssam cp += 2; 43938361Ssam if (changes & TCP_PUSH_BIT) 44038361Ssam th->th_flags |= TH_PUSH; 44138361Ssam else 44238361Ssam th->th_flags &=~ TH_PUSH; 44338361Ssam 44438361Ssam switch (changes & SPECIALS_MASK) { 44538361Ssam case SPECIAL_I: 44638361Ssam { 44738361Ssam register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; 44838361Ssam th->th_ack = htonl(ntohl(th->th_ack) + i); 44938361Ssam th->th_seq = htonl(ntohl(th->th_seq) + i); 45038361Ssam } 45138361Ssam break; 45238361Ssam 45338361Ssam case SPECIAL_D: 45438361Ssam th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) 45538361Ssam - cs->cs_hlen); 45638361Ssam break; 45738361Ssam 45838361Ssam default: 45938361Ssam if (changes & NEW_U) { 46038361Ssam th->th_flags |= TH_URG; 461*39948Ssam DECODEU(th->th_urp) 46238361Ssam } else 46338361Ssam th->th_flags &=~ TH_URG; 46438361Ssam if (changes & NEW_W) 46538361Ssam DECODES(th->th_win) 46638361Ssam if (changes & NEW_A) 46738361Ssam DECODEL(th->th_ack) 46838361Ssam if (changes & NEW_S) 46938361Ssam DECODEL(th->th_seq) 47038361Ssam break; 47138361Ssam } 47238361Ssam if (changes & NEW_I) { 47338361Ssam DECODES(cs->cs_ip.ip_id) 47438361Ssam } else 47538361Ssam cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1); 47638361Ssam 47738361Ssam /* 47838361Ssam * At this point, cp points to the first byte of data in the 47938374Skarels * packet. If we're not aligned on a 4-byte boundary, copy the 48038374Skarels * data down so the ip & tcp headers will be aligned. Then back up 48138374Skarels * cp by the tcp/ip header length to make room for the reconstructed 48238374Skarels * header (we assume the packet we were handed has enough space to 483*39948Ssam * prepend 128 bytes of header). Adjust the length to account for 48438374Skarels * the new header & fill in the IP total length. 48538361Ssam */ 48638374Skarels len -= (cp - *bufp); 487*39948Ssam if (len < 0) 48838374Skarels /* we must have dropped some characters (crc should detect 48938374Skarels * this but the old slip framing won't) */ 490*39948Ssam goto bad; 491*39948Ssam 49238379Ssam if ((int)cp & 3) { 49338379Ssam if (len > 0) 494*39948Ssam (void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len); 49538374Skarels cp = (u_char *)((int)cp &~ 3); 49638374Skarels } 49738374Skarels cp -= cs->cs_hlen; 49838374Skarels len += cs->cs_hlen; 49938374Skarels cs->cs_ip.ip_len = htons(len); 50038374Skarels BCOPY(&cs->cs_ip, cp, cs->cs_hlen); 50138374Skarels *bufp = cp; 50238361Ssam 50338374Skarels /* recompute the ip header checksum */ 50438374Skarels { 50538374Skarels register u_short *bp = (u_short *)cp; 50638374Skarels for (changes = 0; hlen > 0; hlen -= 2) 50738374Skarels changes += *bp++; 50838374Skarels changes = (changes & 0xffff) + (changes >> 16); 50938374Skarels changes = (changes & 0xffff) + (changes >> 16); 51038374Skarels ((struct ip *)cp)->ip_sum = ~ changes; 51138374Skarels } 51238374Skarels return (len); 513*39948Ssam bad: 514*39948Ssam comp->flags |= SLF_TOSS; 515*39948Ssam INCR(sls_errorin) 516*39948Ssam return (0); 51738361Ssam } 518