slcompress.c revision 22975
12258Scsgr/*- 22258Scsgr * Copyright (c) 1989, 1993, 1994 32258Scsgr * The Regents of the University of California. All rights reserved. 42258Scsgr * 52258Scsgr * Redistribution and use in source and binary forms, with or without 62258Scsgr * modification, are permitted provided that the following conditions 72258Scsgr * are met: 82258Scsgr * 1. Redistributions of source code must retain the above copyright 92258Scsgr * notice, this list of conditions and the following disclaimer. 102258Scsgr * 2. Redistributions in binary form must reproduce the above copyright 112258Scsgr * notice, this list of conditions and the following disclaimer in the 122258Scsgr * documentation and/or other materials provided with the distribution. 132258Scsgr * 3. All advertising materials mentioning features or use of this software 142258Scsgr * must display the following acknowledgement: 152258Scsgr * This product includes software developed by the University of 162258Scsgr * California, Berkeley and its contributors. 172258Scsgr * 4. Neither the name of the University nor the names of its contributors 182258Scsgr * may be used to endorse or promote products derived from this software 192258Scsgr * without specific prior written permission. 202258Scsgr * 212258Scsgr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 222258Scsgr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 232258Scsgr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 242258Scsgr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 252258Scsgr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 262258Scsgr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 272258Scsgr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 282258Scsgr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 292258Scsgr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 302258Scsgr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 312258Scsgr * SUCH DAMAGE. 322258Scsgr * 332258Scsgr * @(#)slcompress.c 8.2 (Berkeley) 4/16/94 342258Scsgr * $Id$ 352258Scsgr */ 362258Scsgr 372258Scsgr/* 382258Scsgr * Routines to compress and uncompess tcp packets (for transmission 392258Scsgr * over low speed serial lines. 402258Scsgr * 412258Scsgr * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: 422258Scsgr * - Initial distribution. 432258Scsgr * 442258Scsgr */ 452258Scsgr 462258Scsgr#include <sys/param.h> 472258Scsgr#include <sys/systm.h> 482258Scsgr#include <sys/mbuf.h> 492258Scsgr 502258Scsgr#include <netinet/in.h> 512258Scsgr#include <netinet/in_systm.h> 522258Scsgr#include <netinet/ip.h> 532258Scsgr#include <netinet/tcp.h> 542258Scsgr 552258Scsgr#include <net/slcompress.h> 562258Scsgr 572258Scsgr#ifndef SL_NO_STATS 582258Scsgr#define INCR(counter) ++comp->counter; 592258Scsgr#else 602258Scsgr#define INCR(counter) 612258Scsgr#endif 622258Scsgr 632258Scsgr#define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n)) 642258Scsgr#define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n)) 652258Scsgr#ifndef KERNEL 662258Scsgr#define ovbcopy bcopy 672258Scsgr#endif 682258Scsgr 692258Scsgrvoid 702258Scsgrsl_compress_init(comp, max_state) 712258Scsgr struct slcompress *comp; 722258Scsgr int max_state; 732258Scsgr{ 742258Scsgr register u_int i; 752258Scsgr register struct cstate *tstate = comp->tstate; 762258Scsgr 772258Scsgr if (max_state == -1) 782258Scsgr max_state = MAX_STATES - 1; 792258Scsgr bzero((char *)comp, sizeof(*comp)); 802258Scsgr for (i = max_state; i > 0; --i) { 812258Scsgr tstate[i].cs_id = i; 822258Scsgr tstate[i].cs_next = &tstate[i - 1]; 832258Scsgr } 842258Scsgr tstate[0].cs_next = &tstate[max_state]; 852258Scsgr tstate[0].cs_id = 0; 862258Scsgr comp->last_cs = &tstate[0]; 872258Scsgr comp->last_recv = 255; 882258Scsgr comp->last_xmit = 255; 892258Scsgr comp->flags = SLF_TOSS; 902258Scsgr} 912258Scsgr 922258Scsgr 932258Scsgr/* ENCODE encodes a number that is known to be non-zero. ENCODEZ 942258Scsgr * checks for zero (since zero has to be encoded in the long, 3 byte 952258Scsgr * form). 962258Scsgr */ 972258Scsgr#define ENCODE(n) { \ 982258Scsgr if ((u_short)(n) >= 256) { \ 992258Scsgr *cp++ = 0; \ 1002258Scsgr cp[1] = (n); \ 1012258Scsgr cp[0] = (n) >> 8; \ 1022258Scsgr cp += 2; \ 1032258Scsgr } else { \ 1042258Scsgr *cp++ = (n); \ 1052258Scsgr } \ 1062258Scsgr} 1072258Scsgr#define ENCODEZ(n) { \ 1082258Scsgr if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ 1092258Scsgr *cp++ = 0; \ 1102258Scsgr cp[1] = (n); \ 1112258Scsgr cp[0] = (n) >> 8; \ 1122258Scsgr cp += 2; \ 1132258Scsgr } else { \ 1142258Scsgr *cp++ = (n); \ 1152258Scsgr } \ 1162258Scsgr} 1172258Scsgr 1182258Scsgr#define DECODEL(f) { \ 1192258Scsgr if (*cp == 0) {\ 1202258Scsgr (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \ 1212258Scsgr cp += 3; \ 1222258Scsgr } else { \ 1232258Scsgr (f) = htonl(ntohl(f) + (u_long)*cp++); \ 1242258Scsgr } \ 1252258Scsgr} 1262258Scsgr 1272258Scsgr#define DECODES(f) { \ 1282258Scsgr if (*cp == 0) {\ 1292258Scsgr (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \ 1302258Scsgr cp += 3; \ 1312258Scsgr } else { \ 1322258Scsgr (f) = htons(ntohs(f) + (u_long)*cp++); \ 1332258Scsgr } \ 1342258Scsgr} 1352258Scsgr 1362258Scsgr#define DECODEU(f) { \ 1372258Scsgr if (*cp == 0) {\ 1382258Scsgr (f) = htons((cp[1] << 8) | cp[2]); \ 1392258Scsgr cp += 3; \ 1402258Scsgr } else { \ 1412258Scsgr (f) = htons((u_long)*cp++); \ 1422258Scsgr } \ 1432258Scsgr} 1442258Scsgr 1452258Scsgru_int 1462258Scsgrsl_compress_tcp(m, ip, comp, compress_cid) 1472258Scsgr struct mbuf *m; 1482258Scsgr register struct ip *ip; 1492258Scsgr struct slcompress *comp; 1502258Scsgr int compress_cid; 1512258Scsgr{ 1522258Scsgr register struct cstate *cs = comp->last_cs->cs_next; 1532258Scsgr register u_int hlen = ip->ip_hl; 1542258Scsgr register struct tcphdr *oth; 1552258Scsgr register struct tcphdr *th; 1562258Scsgr register u_int deltaS, deltaA; 1572258Scsgr register u_int changes = 0; 1582258Scsgr u_char new_seq[16]; 1592258Scsgr register u_char *cp = new_seq; 1602258Scsgr 1612258Scsgr /* 1622258Scsgr * Bail if this is an IP fragment or if the TCP packet isn't 1632258Scsgr * `compressible' (i.e., ACK isn't set or some other control bit is 1642258Scsgr * set). (We assume that the caller has already made sure the 1652258Scsgr * packet is IP proto TCP). 1662258Scsgr */ 1672258Scsgr if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40) 1682258Scsgr return (TYPE_IP); 1692258Scsgr 1702258Scsgr th = (struct tcphdr *)&((int *)ip)[hlen]; 1712258Scsgr if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) 1722258Scsgr return (TYPE_IP); 1732258Scsgr /* 1742258Scsgr * Packet is compressible -- we're going to send either a 1752258Scsgr * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need 1762258Scsgr * to locate (or create) the connection state. Special case the 1772258Scsgr * most recently used connection since it's most likely to be used 1782258Scsgr * again & we don't have to do any reordering if it's used. 1792258Scsgr */ 1802258Scsgr INCR(sls_packets) 1812258Scsgr if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || 1822258Scsgr ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || 1832258Scsgr *(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) { 1842258Scsgr /* 1852258Scsgr * Wasn't the first -- search for it. 1862258Scsgr * 1872258Scsgr * States are kept in a circularly linked list with 1882258Scsgr * last_cs pointing to the end of the list. The 1892258Scsgr * list is kept in lru order by moving a state to the 1902258Scsgr * head of the list whenever it is referenced. Since 1912258Scsgr * the list is short and, empirically, the connection 1922258Scsgr * we want is almost always near the front, we locate 1932258Scsgr * states via linear search. If we don't find a state 1942258Scsgr * for the datagram, the oldest state is (re-)used. 1952258Scsgr */ 1962258Scsgr register struct cstate *lcs; 1972258Scsgr register struct cstate *lastcs = comp->last_cs; 1982258Scsgr 1992258Scsgr do { 2002258Scsgr lcs = cs; cs = cs->cs_next; 2012258Scsgr INCR(sls_searches) 2022258Scsgr if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr 2032258Scsgr && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr 2042258Scsgr && *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) 2052258Scsgr goto found; 2062258Scsgr } while (cs != lastcs); 2072258Scsgr 2082258Scsgr /* 2092258Scsgr * Didn't find it -- re-use oldest cstate. Send an 2102258Scsgr * uncompressed packet that tells the other side what 2112258Scsgr * connection number we're using for this conversation. 2122258Scsgr * Note that since the state list is circular, the oldest 2132258Scsgr * state points to the newest and we only need to set 2142258Scsgr * last_cs to update the lru linkage. 2152258Scsgr */ 2162258Scsgr INCR(sls_misses) 2172258Scsgr comp->last_cs = lcs; 2182258Scsgr hlen += th->th_off; 2192258Scsgr hlen <<= 2; 2202258Scsgr goto uncompressed; 2212258Scsgr 2222258Scsgr found: 2232258Scsgr /* 2242258Scsgr * Found it -- move to the front on the connection list. 2252258Scsgr */ 2262258Scsgr if (cs == lastcs) 2272258Scsgr comp->last_cs = lcs; 2282258Scsgr else { 2292258Scsgr lcs->cs_next = cs->cs_next; 2302258Scsgr cs->cs_next = lastcs->cs_next; 2312258Scsgr lastcs->cs_next = cs; 2322258Scsgr } 2332258Scsgr } 2342258Scsgr 2352258Scsgr /* 2362258Scsgr * Make sure that only what we expect to change changed. The first 2372258Scsgr * line of the `if' checks the IP protocol version, header length & 2382258Scsgr * type of service. The 2nd line checks the "Don't fragment" bit. 2392258Scsgr * The 3rd line checks the time-to-live and protocol (the protocol 2402258Scsgr * check is unnecessary but costless). The 4th line checks the TCP 2412258Scsgr * header length. The 5th line checks IP options, if any. The 6th 2422258Scsgr * line checks TCP options, if any. If any of these things are 2432258Scsgr * different between the previous & current datagram, we send the 2442258Scsgr * current datagram `uncompressed'. 2452258Scsgr */ 2462258Scsgr oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen]; 2472258Scsgr deltaS = hlen; 2482258Scsgr hlen += th->th_off; 2492258Scsgr hlen <<= 2; 2502258Scsgr 2512258Scsgr if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] || 2522258Scsgr ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] || 2532258Scsgr ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] || 2542258Scsgr th->th_off != oth->th_off || 2552258Scsgr (deltaS > 5 && 2562258Scsgr BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || 2572258Scsgr (th->th_off > 5 && 2582258Scsgr BCMP(th + 1, oth + 1, (th->th_off - 5) << 2))) 2592258Scsgr goto uncompressed; 2602258Scsgr 2612258Scsgr /* 2622258Scsgr * Figure out which of the changing fields changed. The 2632258Scsgr * receiver expects changes in the order: urgent, window, 2642258Scsgr * ack, seq (the order minimizes the number of temporaries 2652258Scsgr * needed in this section of code). 2662258Scsgr */ 2672258Scsgr if (th->th_flags & TH_URG) { 2682258Scsgr deltaS = ntohs(th->th_urp); 2692258Scsgr ENCODEZ(deltaS); 2702258Scsgr changes |= NEW_U; 2712258Scsgr } else if (th->th_urp != oth->th_urp) 2722258Scsgr /* argh! URG not set but urp changed -- a sensible 2732258Scsgr * implementation should never do this but RFC793 2742258Scsgr * doesn't prohibit the change so we have to deal 2752258Scsgr * with it. */ 2762258Scsgr goto uncompressed; 2772258Scsgr 2782258Scsgr deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win)); 2792258Scsgr if (deltaS) { 2802258Scsgr ENCODE(deltaS); 2812258Scsgr changes |= NEW_W; 2822258Scsgr } 2832258Scsgr 2842258Scsgr deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack); 2852258Scsgr if (deltaA) { 2862258Scsgr if (deltaA > 0xffff) 2872258Scsgr goto uncompressed; 2882258Scsgr ENCODE(deltaA); 2892258Scsgr changes |= NEW_A; 2902258Scsgr } 2912258Scsgr 2922258Scsgr deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq); 2932258Scsgr if (deltaS) { 2942258Scsgr if (deltaS > 0xffff) 2952258Scsgr goto uncompressed; 2962258Scsgr ENCODE(deltaS); 2972258Scsgr changes |= NEW_S; 2982258Scsgr } 2992258Scsgr 3002258Scsgr switch(changes) { 3012258Scsgr 3022258Scsgr case 0: 3032258Scsgr /* 3042258Scsgr * Nothing changed. If this packet contains data and the 3052258Scsgr * last one didn't, this is probably a data packet following 3062258Scsgr * an ack (normal on an interactive connection) and we send 3072258Scsgr * it compressed. Otherwise it's probably a retransmit, 3082258Scsgr * retransmitted ack or window probe. Send it uncompressed 3092258Scsgr * in case the other side missed the compressed version. 3102258Scsgr */ 3112258Scsgr if (ip->ip_len != cs->cs_ip.ip_len && 3122258Scsgr ntohs(cs->cs_ip.ip_len) == hlen) 3132258Scsgr break; 3142258Scsgr 3152258Scsgr /* (fall through) */ 3162258Scsgr 3172258Scsgr case SPECIAL_I: 3182258Scsgr case SPECIAL_D: 3192258Scsgr /* 3202258Scsgr * actual changes match one of our special case encodings -- 3212258Scsgr * send packet uncompressed. 3222258Scsgr */ 3232258Scsgr goto uncompressed; 3242258Scsgr 3252258Scsgr case NEW_S|NEW_A: 3262258Scsgr if (deltaS == deltaA && 3272258Scsgr deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { 3282258Scsgr /* special case for echoed terminal traffic */ 3292258Scsgr changes = SPECIAL_I; 3302258Scsgr cp = new_seq; 3312258Scsgr } 3322258Scsgr break; 3332258Scsgr 3342258Scsgr case NEW_S: 3352258Scsgr if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { 3362258Scsgr /* special case for data xfer */ 3372258Scsgr changes = SPECIAL_D; 3382258Scsgr cp = new_seq; 3392258Scsgr } 3402258Scsgr break; 3412258Scsgr } 3422258Scsgr 3432258Scsgr deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); 3442258Scsgr if (deltaS != 1) { 3452258Scsgr ENCODEZ(deltaS); 3462258Scsgr changes |= NEW_I; 3472258Scsgr } 3482258Scsgr if (th->th_flags & TH_PUSH) 3492258Scsgr changes |= TCP_PUSH_BIT; 3502258Scsgr /* 3512258Scsgr * Grab the cksum before we overwrite it below. Then update our 3522258Scsgr * state with this packet's header. 3532258Scsgr */ 3542258Scsgr deltaA = ntohs(th->th_sum); 3552258Scsgr BCOPY(ip, &cs->cs_ip, hlen); 3562258Scsgr 3572258Scsgr /* 3582258Scsgr * We want to use the original packet as our compressed packet. 3592258Scsgr * (cp - new_seq) is the number of bytes we need for compressed 3602258Scsgr * sequence numbers. In addition we need one byte for the change 3612258Scsgr * mask, one for the connection id and two for the tcp checksum. 3622258Scsgr * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how 3632258Scsgr * many bytes of the original packet to toss so subtract the two to 3642258Scsgr * get the new packet size. 3652258Scsgr */ 3662258Scsgr deltaS = cp - new_seq; 3672258Scsgr cp = (u_char *)ip; 3682258Scsgr if (compress_cid == 0 || comp->last_xmit != cs->cs_id) { 3692258Scsgr comp->last_xmit = cs->cs_id; 3702258Scsgr hlen -= deltaS + 4; 3712258Scsgr cp += hlen; 3722258Scsgr *cp++ = changes | NEW_C; 3732258Scsgr *cp++ = cs->cs_id; 3742258Scsgr } else { 3752258Scsgr hlen -= deltaS + 3; 3762258Scsgr cp += hlen; 3772258Scsgr *cp++ = changes; 3782258Scsgr } 3792258Scsgr m->m_len -= hlen; 3802258Scsgr m->m_data += hlen; 3812258Scsgr *cp++ = deltaA >> 8; 3822258Scsgr *cp++ = deltaA; 3832258Scsgr BCOPY(new_seq, cp, deltaS); 3842258Scsgr INCR(sls_compressed) 3852258Scsgr return (TYPE_COMPRESSED_TCP); 3862258Scsgr 3872258Scsgr /* 3882258Scsgr * Update connection state cs & send uncompressed packet ('uncompressed' 3892258Scsgr * means a regular ip/tcp packet but with the 'conversation id' we hope 3902258Scsgr * to use on future compressed packets in the protocol field). 3912258Scsgr */ 3922258Scsgruncompressed: 3932258Scsgr BCOPY(ip, &cs->cs_ip, hlen); 3942258Scsgr ip->ip_p = cs->cs_id; 3952258Scsgr comp->last_xmit = cs->cs_id; 3962258Scsgr return (TYPE_UNCOMPRESSED_TCP); 3972258Scsgr} 3982258Scsgr 3992258Scsgr 4002258Scsgrint 4012258Scsgrsl_uncompress_tcp(bufp, len, type, comp) 4022258Scsgr u_char **bufp; 4032258Scsgr int len; 4042258Scsgr u_int type; 4052258Scsgr struct slcompress *comp; 4062258Scsgr{ 4072258Scsgr u_char *hdr, *cp; 4082258Scsgr int hlen, vjlen; 4092258Scsgr 4102258Scsgr cp = bufp? *bufp: NULL; 4112258Scsgr vjlen = sl_uncompress_tcp_core(cp, len, len, type, comp, &hdr, &hlen); 4122258Scsgr if (vjlen < 0) 4132258Scsgr return (0); /* error */ 4142258Scsgr if (vjlen == 0) 4152258Scsgr return (len); /* was uncompressed already */ 4162258Scsgr 4172258Scsgr cp += vjlen; 4182258Scsgr len -= vjlen; 4192258Scsgr 4202258Scsgr /* 4212258Scsgr * At this point, cp points to the first byte of data in the 4222258Scsgr * packet. If we're not aligned on a 4-byte boundary, copy the 4232258Scsgr * data down so the ip & tcp headers will be aligned. Then back up 4242258Scsgr * cp by the tcp/ip header length to make room for the reconstructed 4252258Scsgr * header (we assume the packet we were handed has enough space to 4262258Scsgr * prepend 128 bytes of header). 4272258Scsgr */ 4282258Scsgr if ((int)cp & 3) { 4292258Scsgr if (len > 0) 4302258Scsgr (void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len); 4312258Scsgr cp = (u_char *)((int)cp &~ 3); 4322258Scsgr } 4332258Scsgr cp -= hlen; 4342258Scsgr len += hlen; 4352258Scsgr BCOPY(hdr, cp, hlen); 4362258Scsgr 4372258Scsgr *bufp = cp; 4382258Scsgr return (len); 4392258Scsgr} 4402258Scsgr 4412258Scsgr/* 4422258Scsgr * Uncompress a packet of total length total_len. The first buflen 4432258Scsgr * bytes are at buf; this must include the entire (compressed or 4442258Scsgr * uncompressed) TCP/IP header. This procedure returns the length 4452258Scsgr * of the VJ header, with a pointer to the uncompressed IP header 4462258Scsgr * in *hdrp and its length in *hlenp. 4472258Scsgr */ 4482258Scsgrint 4492258Scsgrsl_uncompress_tcp_core(buf, buflen, total_len, type, comp, hdrp, hlenp) 4502258Scsgr u_char *buf; 4512258Scsgr int buflen, total_len; 4522258Scsgr u_int type; 4532258Scsgr struct slcompress *comp; 4542258Scsgr u_char **hdrp; 4552258Scsgr u_int *hlenp; 4562258Scsgr{ 4572258Scsgr register u_char *cp; 4582258Scsgr register u_int hlen, changes; 4592258Scsgr register struct tcphdr *th; 4602258Scsgr register struct cstate *cs; 4612258Scsgr register struct ip *ip; 4622258Scsgr register u_short *bp; 4632258Scsgr register u_int vjlen; 4642258Scsgr 4652258Scsgr switch (type) { 4662258Scsgr 4672258Scsgr case TYPE_UNCOMPRESSED_TCP: 4682258Scsgr ip = (struct ip *) buf; 4692258Scsgr if (ip->ip_p >= MAX_STATES) 4702258Scsgr goto bad; 4712258Scsgr cs = &comp->rstate[comp->last_recv = ip->ip_p]; 4722258Scsgr comp->flags &=~ SLF_TOSS; 4732258Scsgr ip->ip_p = IPPROTO_TCP; 4742258Scsgr /* 4752258Scsgr * Calculate the size of the TCP/IP header and make sure that 4762258Scsgr * we don't overflow the space we have available for it. 4772258Scsgr */ 4782258Scsgr hlen = ip->ip_hl << 2; 4792258Scsgr if (hlen + sizeof(struct tcphdr) > buflen) 4802258Scsgr goto bad; 4812258Scsgr hlen += ((struct tcphdr *)&((char *)ip)[hlen])->th_off << 2; 4822258Scsgr if (hlen > MAX_HDR) 4832258Scsgr goto bad; 4842258Scsgr BCOPY(ip, &cs->cs_ip, hlen); 4852258Scsgr cs->cs_hlen = hlen; 4862258Scsgr INCR(sls_uncompressedin) 4872258Scsgr *hdrp = (u_char *) &cs->cs_ip; 4882258Scsgr *hlenp = hlen; 4892258Scsgr return (0); 4902258Scsgr 4912258Scsgr default: 4922258Scsgr goto bad; 4932258Scsgr 4942258Scsgr case TYPE_COMPRESSED_TCP: 4952258Scsgr break; 4962258Scsgr } 4972258Scsgr /* We've got a compressed packet. */ 4982258Scsgr INCR(sls_compressedin) 4992258Scsgr cp = buf; 5002258Scsgr changes = *cp++; 5012258Scsgr if (changes & NEW_C) { 5022258Scsgr /* Make sure the state index is in range, then grab the state. 5032258Scsgr * If we have a good state index, clear the 'discard' flag. */ 5042258Scsgr if (*cp >= MAX_STATES) 5052258Scsgr goto bad; 5062258Scsgr 5072258Scsgr comp->flags &=~ SLF_TOSS; 5082258Scsgr comp->last_recv = *cp++; 5092258Scsgr } else { 5102258Scsgr /* this packet has an implicit state index. If we've 5112258Scsgr * had a line error since the last time we got an 5122258Scsgr * explicit state index, we have to toss the packet. */ 5132258Scsgr if (comp->flags & SLF_TOSS) { 5142258Scsgr INCR(sls_tossed) 5152258Scsgr return (-1); 5162258Scsgr } 5172258Scsgr } 5182258Scsgr cs = &comp->rstate[comp->last_recv]; 5192258Scsgr hlen = cs->cs_ip.ip_hl << 2; 5202258Scsgr th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; 5212258Scsgr th->th_sum = htons((*cp << 8) | cp[1]); 5222258Scsgr cp += 2; 5232258Scsgr if (changes & TCP_PUSH_BIT) 5242258Scsgr th->th_flags |= TH_PUSH; 5252258Scsgr else 5262258Scsgr th->th_flags &=~ TH_PUSH; 5272258Scsgr 5282258Scsgr switch (changes & SPECIALS_MASK) { 5292258Scsgr case SPECIAL_I: 5302258Scsgr { 5312258Scsgr register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; 5322258Scsgr th->th_ack = htonl(ntohl(th->th_ack) + i); 5332258Scsgr th->th_seq = htonl(ntohl(th->th_seq) + i); 5342258Scsgr } 5352258Scsgr break; 5362258Scsgr 5372258Scsgr case SPECIAL_D: 5382258Scsgr th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) 5392258Scsgr - cs->cs_hlen); 5402258Scsgr break; 5412258Scsgr 5422258Scsgr default: 5432258Scsgr if (changes & NEW_U) { 5442258Scsgr th->th_flags |= TH_URG; 5452258Scsgr DECODEU(th->th_urp) 5462258Scsgr } else 5472258Scsgr th->th_flags &=~ TH_URG; 5482258Scsgr if (changes & NEW_W) 5492258Scsgr DECODES(th->th_win) 5502258Scsgr if (changes & NEW_A) 5512258Scsgr DECODEL(th->th_ack) 5522258Scsgr if (changes & NEW_S) 5532258Scsgr DECODEL(th->th_seq) 5542258Scsgr break; 5552258Scsgr } 5562258Scsgr if (changes & NEW_I) { 5572258Scsgr DECODES(cs->cs_ip.ip_id) 5582258Scsgr } else 5592258Scsgr cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1); 5602258Scsgr 5612258Scsgr /* 5622258Scsgr * At this point, cp points to the first byte of data in the 5632258Scsgr * packet. Fill in the IP total length and update the IP 5642258Scsgr * header checksum. 5652258Scsgr */ 5662258Scsgr vjlen = cp - buf; 5672258Scsgr buflen -= vjlen; 5682258Scsgr if (buflen < 0) 5692258Scsgr /* we must have dropped some characters (crc should detect 5702258Scsgr * this but the old slip framing won't) */ 5712258Scsgr goto bad; 5722258Scsgr 5732258Scsgr total_len += cs->cs_hlen - vjlen; 5742258Scsgr cs->cs_ip.ip_len = htons(total_len); 5752258Scsgr 5762258Scsgr /* recompute the ip header checksum */ 5772258Scsgr bp = (u_short *) &cs->cs_ip; 5782258Scsgr cs->cs_ip.ip_sum = 0; 5792258Scsgr for (changes = 0; hlen > 0; hlen -= 2) 5802258Scsgr changes += *bp++; 5812258Scsgr changes = (changes & 0xffff) + (changes >> 16); 5822258Scsgr changes = (changes & 0xffff) + (changes >> 16); 5832258Scsgr cs->cs_ip.ip_sum = ~ changes; 5842258Scsgr 5852258Scsgr *hdrp = (u_char *) &cs->cs_ip; 5862258Scsgr *hlenp = cs->cs_hlen; 5872258Scsgr return vjlen; 5882258Scsgr 5892258Scsgrbad: 5902258Scsgr comp->flags |= SLF_TOSS; 5912258Scsgr INCR(sls_errorin) 5922258Scsgr return (-1); 5932258Scsgr} 5942258Scsgr