slcompress.c revision 26516
16059Samurai/*
26059Samurai * Routines to compress and uncompess tcp packets (for transmission
36059Samurai * over low speed serial lines.
46059Samurai *
56059Samurai * Copyright (c) 1989 Regents of the University of California.
66059Samurai * All rights reserved.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the University of California, Berkeley.  The name of the
146059Samurai * University may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
196059Samurai *
2026516Sbrian * $Id: slcompress.c,v 1.8 1997/02/22 16:10:54 peter Exp $
218857Srgrimes *
226059Samurai *	Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
236059Samurai *	- Initial distribution.
246059Samurai */
256059Samurai#ifndef lint
2626516Sbrianstatic char const rcsid[] = "$Id: slcompress.c,v 1.8 1997/02/22 16:10:54 peter Exp $";
276059Samurai#endif
286059Samurai
296059Samurai#include "defs.h"
306059Samurai#include <netinet/in_systm.h>
316059Samurai#include <netinet/in.h>
326059Samurai#include <netinet/tcp.h>
336059Samurai#include <netinet/ip.h>
346059Samurai#include "slcompress.h"
3526516Sbrian#include "loadalias.h"
3626516Sbrian#include "vars.h"
376059Samurai
386059Samuraistruct slstat slstat;
396059Samurai
406059Samurai#define INCR(counter)	slstat.counter++;
416059Samurai
426059Samurai#define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n))
436059Samurai#define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n))
446059Samurai#ifndef KERNEL
456059Samurai#define ovbcopy bcopy
466059Samurai#endif
476059Samurai
486059Samuraivoid
496059Samuraisl_compress_init(comp)
506059Samurai	struct slcompress *comp;
516059Samurai{
526059Samurai	register u_int i;
536059Samurai	register struct cstate *tstate = comp->tstate;
546059Samurai
556059Samurai	bzero((char *)comp, sizeof(*comp));
566059Samurai	for (i = MAX_STATES - 1; i > 0; --i) {
576059Samurai		tstate[i].cs_id = i;
586059Samurai		tstate[i].cs_next = &tstate[i - 1];
596059Samurai	}
606059Samurai	tstate[0].cs_next = &tstate[MAX_STATES - 1];
616059Samurai	tstate[0].cs_id = 0;
626059Samurai	comp->last_cs = &tstate[0];
636059Samurai	comp->last_recv = 255;
646059Samurai	comp->last_xmit = 255;
656059Samurai	comp->flags = SLF_TOSS;
666059Samurai}
676059Samurai
686059Samurai
696059Samurai/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
706059Samurai * checks for zero (since zero has to be encoded in the long, 3 byte
716059Samurai * form).
726059Samurai */
736059Samurai#define ENCODE(n) { \
746059Samurai	if ((u_short)(n) >= 256) { \
756059Samurai		*cp++ = 0; \
766059Samurai		cp[1] = (n); \
776059Samurai		cp[0] = (n) >> 8; \
786059Samurai		cp += 2; \
796059Samurai	} else { \
806059Samurai		*cp++ = (n); \
816059Samurai	} \
826059Samurai}
836059Samurai#define ENCODEZ(n) { \
846059Samurai	if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
856059Samurai		*cp++ = 0; \
866059Samurai		cp[1] = (n); \
876059Samurai		cp[0] = (n) >> 8; \
886059Samurai		cp += 2; \
896059Samurai	} else { \
906059Samurai		*cp++ = (n); \
916059Samurai	} \
926059Samurai}
936059Samurai
946059Samurai#define DECODEL(f) { \
956059Samurai	if (*cp == 0) {\
966059Samurai		(f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
976059Samurai		cp += 3; \
986059Samurai	} else { \
996059Samurai		(f) = htonl(ntohl(f) + (u_long)*cp++); \
1006059Samurai	} \
1016059Samurai}
1026059Samurai
1036059Samurai#define DECODES(f) { \
1046059Samurai	if (*cp == 0) {\
1056059Samurai		(f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
1066059Samurai		cp += 3; \
1076059Samurai	} else { \
1086059Samurai		(f) = htons(ntohs(f) + (u_long)*cp++); \
1096059Samurai	} \
1106059Samurai}
1116059Samurai
1126059Samurai#define DECODEU(f) { \
1136059Samurai	if (*cp == 0) {\
1146059Samurai		(f) = htons((cp[1] << 8) | cp[2]); \
1156059Samurai		cp += 3; \
1166059Samurai	} else { \
1176059Samurai		(f) = htons((u_long)*cp++); \
1186059Samurai	} \
1196059Samurai}
1206059Samurai
1216059Samurai
1226059Samuraiu_char
1236059Samuraisl_compress_tcp(m, ip, comp, compress_cid)
1246059Samurai	struct mbuf *m;
1256059Samurai	register struct ip *ip;
1266059Samurai	struct slcompress *comp;
1276059Samurai	int compress_cid;
1286059Samurai{
1296059Samurai	register struct cstate *cs = comp->last_cs->cs_next;
1306059Samurai	register u_int hlen = ip->ip_hl;
1316059Samurai	register struct tcphdr *oth;
1326059Samurai	register struct tcphdr *th;
1336059Samurai	register u_int deltaS, deltaA;
1346059Samurai	register u_int changes = 0;
1356059Samurai	u_char new_seq[16];
1366059Samurai	register u_char *cp = new_seq;
1376059Samurai
1386059Samurai	/*
1396059Samurai	 * Bail if this is an IP fragment or if the TCP packet isn't
1406059Samurai	 * `compressible' (i.e., ACK isn't set or some other control bit is
1416059Samurai	 * set).  (We assume that the caller has already made sure the
1426059Samurai	 * packet is IP proto TCP).
1436059Samurai	 */
1446059Samurai	if ((ip->ip_off & htons(0x3fff)) || m->cnt < 40) {
14526516Sbrian		LogPrintf(LogDEBUG, "??? 1 ip_off = %x, cnt = %d\n",
14626516Sbrian			ip->ip_off, m->cnt);
14726516Sbrian		LogDumpBp(LogDEBUG, "", m);
1486059Samurai		return (TYPE_IP);
1496059Samurai	}
1506059Samurai
1516059Samurai	th = (struct tcphdr *)&((int *)ip)[hlen];
1526059Samurai	if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) {
15326516Sbrian		LogPrintf(LogDEBUG, "??? 2 th_flags = %x\n", th->th_flags);
15426516Sbrian		LogDumpBp(LogDEBUG, "", m);
1556059Samurai		return (TYPE_IP);
1566059Samurai	}
1576059Samurai
1586059Samurai	/*
1596059Samurai	 * Packet is compressible -- we're going to send either a
1606059Samurai	 * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
1616059Samurai	 * to locate (or create) the connection state.  Special case the
1626059Samurai	 * most recently used connection since it's most likely to be used
1636059Samurai	 * again & we don't have to do any reordering if it's used.
1646059Samurai	 */
1656059Samurai	INCR(sls_packets)
1666059Samurai	if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
1676059Samurai	    ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
1686059Samurai	    *(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) {
1696059Samurai		/*
1706059Samurai		 * Wasn't the first -- search for it.
1716059Samurai		 *
1726059Samurai		 * States are kept in a circularly linked list with
1736059Samurai		 * last_cs pointing to the end of the list.  The
1746059Samurai		 * list is kept in lru order by moving a state to the
1756059Samurai		 * head of the list whenever it is referenced.  Since
1766059Samurai		 * the list is short and, empirically, the connection
1776059Samurai		 * we want is almost always near the front, we locate
1786059Samurai		 * states via linear search.  If we don't find a state
1796059Samurai		 * for the datagram, the oldest state is (re-)used.
1806059Samurai		 */
1816059Samurai		register struct cstate *lcs;
1826059Samurai		register struct cstate *lastcs = comp->last_cs;
1836059Samurai
1846059Samurai		do {
1856059Samurai			lcs = cs; cs = cs->cs_next;
1866059Samurai			INCR(sls_searches)
1876059Samurai			if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
1886059Samurai			    && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
1896059Samurai			    && *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl])
1906059Samurai				goto found;
1916059Samurai		} while (cs != lastcs);
1926059Samurai
1936059Samurai		/*
1946059Samurai		 * Didn't find it -- re-use oldest cstate.  Send an
1956059Samurai		 * uncompressed packet that tells the other side what
1966059Samurai		 * connection number we're using for this conversation.
1976059Samurai		 * Note that since the state list is circular, the oldest
1986059Samurai		 * state points to the newest and we only need to set
1996059Samurai		 * last_cs to update the lru linkage.
2006059Samurai		 */
2016059Samurai		INCR(sls_misses)
2026059Samurai		comp->last_cs = lcs;
2036059Samurai#define	THOFFSET(th)	(th->th_off)
2046059Samurai		hlen += th->th_off;
2056059Samurai		hlen <<= 2;
2066059Samurai		if (hlen > m->cnt)
2076059Samurai			return(TYPE_IP);
2086059Samurai		goto uncompressed;
2096059Samurai
2106059Samurai	found:
2116059Samurai		/*
2126059Samurai		 * Found it -- move to the front on the connection list.
2136059Samurai		 */
2146059Samurai		if (cs == lastcs)
2156059Samurai			comp->last_cs = lcs;
2166059Samurai		else {
2176059Samurai			lcs->cs_next = cs->cs_next;
2186059Samurai			cs->cs_next = lastcs->cs_next;
2196059Samurai			lastcs->cs_next = cs;
2206059Samurai		}
2216059Samurai	}
2226059Samurai
2236059Samurai	/*
2246059Samurai	 * Make sure that only what we expect to change changed. The first
2256059Samurai	 * line of the `if' checks the IP protocol version, header length &
2266059Samurai	 * type of service.  The 2nd line checks the "Don't fragment" bit.
2276059Samurai	 * The 3rd line checks the time-to-live and protocol (the protocol
2286059Samurai	 * check is unnecessary but costless).  The 4th line checks the TCP
2296059Samurai	 * header length.  The 5th line checks IP options, if any.  The 6th
2306059Samurai	 * line checks TCP options, if any.  If any of these things are
2316059Samurai	 * different between the previous & current datagram, we send the
2326059Samurai	 * current datagram `uncompressed'.
2336059Samurai	 */
2346059Samurai	oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen];
2356059Samurai	deltaS = hlen;
2366059Samurai	hlen += th->th_off;
2376059Samurai	hlen <<= 2;
2386059Samurai	if (hlen > m->cnt)
2396059Samurai		return(TYPE_IP);
2406059Samurai
2416059Samurai	if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] ||
2426059Samurai	    ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] ||
2436059Samurai	    ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] ||
2446059Samurai	    THOFFSET(th) != THOFFSET(oth) ||
2456059Samurai	    (deltaS > 5 &&
2466059Samurai	     BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
2476059Samurai	    (THOFFSET(th) > 5 &&
2486059Samurai	     BCMP(th + 1, oth + 1, (THOFFSET(th) - 5) << 2))) {
2496059Samurai		goto uncompressed;
2506059Samurai	}
2516059Samurai
2526059Samurai	/*
2536059Samurai	 * Figure out which of the changing fields changed.  The
2546059Samurai	 * receiver expects changes in the order: urgent, window,
2556059Samurai	 * ack, seq (the order minimizes the number of temporaries
2566059Samurai	 * needed in this section of code).
2576059Samurai	 */
2586059Samurai	if (th->th_flags & TH_URG) {
2596059Samurai		deltaS = ntohs(th->th_urp);
2606059Samurai		ENCODEZ(deltaS);
2616059Samurai		changes |= NEW_U;
2626059Samurai	} else if (th->th_urp != oth->th_urp) {
2636059Samurai		/* argh! URG not set but urp changed -- a sensible
2646059Samurai		 * implementation should never do this but RFC793
2656059Samurai		 * doesn't prohibit the change so we have to deal
2666059Samurai		 * with it. */
2676059Samurai		 goto uncompressed;
2686059Samurai	}
2696059Samurai
2706059Samurai	deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win));
2716059Samurai	if (deltaS) {
2726059Samurai		ENCODE(deltaS);
2736059Samurai		changes |= NEW_W;
2746059Samurai	}
2756059Samurai
2766059Samurai	deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack);
2776059Samurai	if (deltaA) {
2786059Samurai		if (deltaA > 0xffff) {
2796059Samurai			goto uncompressed;
2806059Samurai		}
2816059Samurai		ENCODE(deltaA);
2826059Samurai		changes |= NEW_A;
2836059Samurai	}
2846059Samurai
2856059Samurai	deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq);
2866059Samurai	if (deltaS) {
2876059Samurai		if (deltaS > 0xffff) {
2886059Samurai			goto uncompressed;
2896059Samurai		}
2906059Samurai		ENCODE(deltaS);
2916059Samurai		changes |= NEW_S;
2926059Samurai	}
2936059Samurai
2946059Samurai	switch(changes) {
2956059Samurai
2966059Samurai	case 0:
2976059Samurai		/*
2986059Samurai		 * Nothing changed. If this packet contains data and the
2996059Samurai		 * last one didn't, this is probably a data packet following
3006059Samurai		 * an ack (normal on an interactive connection) and we send
3016059Samurai		 * it compressed.  Otherwise it's probably a retransmit,
3026059Samurai		 * retransmitted ack or window probe.  Send it uncompressed
3036059Samurai		 * in case the other side missed the compressed version.
3046059Samurai		 */
3056059Samurai		if (ip->ip_len != cs->cs_ip.ip_len &&
3066059Samurai		    ntohs(cs->cs_ip.ip_len) == hlen)
3076059Samurai			break;
3086059Samurai
3096059Samurai		/* (fall through) */
3106059Samurai
3116059Samurai	case SPECIAL_I:
3126059Samurai	case SPECIAL_D:
3136059Samurai		/*
3146059Samurai		 * actual changes match one of our special case encodings --
3156059Samurai		 * send packet uncompressed.
3166059Samurai		 */
3176059Samurai		goto uncompressed;
3186059Samurai
3196059Samurai	case NEW_S|NEW_A:
3206059Samurai		if (deltaS == deltaA &&
3216059Samurai		    deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
3226059Samurai			/* special case for echoed terminal traffic */
3236059Samurai			changes = SPECIAL_I;
3246059Samurai			cp = new_seq;
3256059Samurai		}
3266059Samurai		break;
3276059Samurai
3286059Samurai	case NEW_S:
3296059Samurai		if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
3306059Samurai			/* special case for data xfer */
3316059Samurai			changes = SPECIAL_D;
3326059Samurai			cp = new_seq;
3336059Samurai		}
3346059Samurai		break;
3356059Samurai	}
3366059Samurai
3376059Samurai	deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
3386059Samurai	if (deltaS != 1) {
3396059Samurai		ENCODEZ(deltaS);
3406059Samurai		changes |= NEW_I;
3416059Samurai	}
3426059Samurai	if (th->th_flags & TH_PUSH)
3436059Samurai		changes |= TCP_PUSH_BIT;
3446059Samurai	/*
3456059Samurai	 * Grab the cksum before we overwrite it below.  Then update our
3466059Samurai	 * state with this packet's header.
3476059Samurai	 */
3486059Samurai	deltaA = ntohs(th->th_sum);
3496059Samurai	BCOPY(ip, &cs->cs_ip, hlen);
3506059Samurai
3516059Samurai	/*
3526059Samurai	 * We want to use the original packet as our compressed packet.
3536059Samurai	 * (cp - new_seq) is the number of bytes we need for compressed
3546059Samurai	 * sequence numbers.  In addition we need one byte for the change
3556059Samurai	 * mask, one for the connection id and two for the tcp checksum.
3566059Samurai	 * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
3576059Samurai	 * many bytes of the original packet to toss so subtract the two to
3586059Samurai	 * get the new packet size.
3596059Samurai	 */
3606059Samurai	deltaS = cp - new_seq;
3616059Samurai	cp = (u_char *)ip;
3626059Samurai
3636059Samurai        /*
3646059Samurai         * Since fastq traffic can jump ahead of the background traffic,
3656059Samurai         * we don't know what order packets will go on the line.  In this
3666059Samurai         * case, we always send a "new" connection id so the receiver state
3676059Samurai         * stays synchronized.
3686059Samurai         */
3696059Samurai#ifdef SL_NOFASTQ
3706059Samurai        if (comp->last_xmit == cs->cs_id) {
3716059Samurai                hlen -= deltaS + 3;
3726059Samurai                cp += hlen;
3736059Samurai                *cp++ = changes;
3746059Samurai        } else
3756059Samurai#endif
3766059Samurai	{
3776059Samurai		comp->last_xmit = cs->cs_id;
3786059Samurai		hlen -= deltaS + 4;
3796059Samurai		cp += hlen;
3806059Samurai		*cp++ = changes | NEW_C;
3816059Samurai		*cp++ = cs->cs_id;
3826059Samurai	}
3836059Samurai	m->cnt -= hlen;
3846059Samurai	m->offset += hlen;
3856059Samurai	*cp++ = deltaA >> 8;
3866059Samurai	*cp++ = deltaA;
3876059Samurai	BCOPY(new_seq, cp, deltaS);
3886059Samurai	INCR(sls_compressed)
3896059Samurai	return (TYPE_COMPRESSED_TCP);
3906059Samurai
3916059Samurai	/*
3926059Samurai	 * Update connection state cs & send uncompressed packet ('uncompressed'
3936059Samurai	 * means a regular ip/tcp packet but with the 'conversation id' we hope
3946059Samurai	 * to use on future compressed packets in the protocol field).
3956059Samurai	 */
3966059Samuraiuncompressed:
3976059Samurai	BCOPY(ip, &cs->cs_ip, hlen);
3986059Samurai	ip->ip_p = cs->cs_id;
3996059Samurai	comp->last_xmit = cs->cs_id;
4006059Samurai	return (TYPE_UNCOMPRESSED_TCP);
4016059Samurai}
4026059Samurai
4036059Samurai
4046059Samuraiint
4056059Samuraisl_uncompress_tcp(bufp, len, type, comp)
4066059Samurai	u_char **bufp;
4076059Samurai	int len;
4086059Samurai	u_int type;
4096059Samurai	struct slcompress *comp;
4106059Samurai{
4116059Samurai	register u_char *cp;
4126059Samurai	register u_int hlen, changes;
4136059Samurai	register struct tcphdr *th;
4146059Samurai	register struct cstate *cs;
4156059Samurai	register struct ip *ip;
4166059Samurai
4176059Samurai	switch (type) {
4186059Samurai
4196059Samurai	case TYPE_UNCOMPRESSED_TCP:
4206059Samurai		ip = (struct ip *) *bufp;
4216059Samurai		if (ip->ip_p >= MAX_STATES)
4226059Samurai			goto bad;
4236059Samurai		cs = &comp->rstate[comp->last_recv = ip->ip_p];
4246059Samurai		comp->flags &=~ SLF_TOSS;
4256059Samurai		ip->ip_p = IPPROTO_TCP;
42615190Sdg		/*
42715190Sdg		 * Calculate the size of the TCP/IP header and make sure that
42815190Sdg		 * we don't overflow the space we have available for it.
42915190Sdg		*/
43015190Sdg		hlen = ip->ip_hl << 2;
43115190Sdg		if (hlen + sizeof(struct tcphdr) > len)
43215190Sdg			goto bad;
43315193Sdg		th = (struct tcphdr *)&((char *)ip)[hlen];
43415190Sdg		hlen += THOFFSET(th) << 2;
43515190Sdg		if (hlen > MAX_HDR)
43615190Sdg			goto bad;
4376059Samurai		BCOPY(ip, &cs->cs_ip, hlen);
4386059Samurai		cs->cs_ip.ip_sum = 0;
4396059Samurai		cs->cs_hlen = hlen;
4406059Samurai		INCR(sls_uncompressedin)
4416059Samurai		return (len);
4426059Samurai
4436059Samurai	default:
4446059Samurai		goto bad;
4456059Samurai
4466059Samurai	case TYPE_COMPRESSED_TCP:
4476059Samurai		break;
4486059Samurai	}
4496059Samurai	/* We've got a compressed packet. */
4506059Samurai	INCR(sls_compressedin)
4516059Samurai	cp = *bufp;
4526059Samurai	changes = *cp++;
45326516Sbrian	LogPrintf(LogDEBUG, "compressed: changes = %02x\n", changes);
4546059Samurai	if (changes & NEW_C) {
4556059Samurai		/* Make sure the state index is in range, then grab the state.
4566059Samurai		 * If we have a good state index, clear the 'discard' flag. */
4576735Samurai		if (*cp >= MAX_STATES || comp->last_recv == 255)
4586059Samurai			goto bad;
4596059Samurai
4606059Samurai		comp->flags &=~ SLF_TOSS;
4616059Samurai		comp->last_recv = *cp++;
4626059Samurai	} else {
4636059Samurai		/* this packet has an implicit state index.  If we've
4646059Samurai		 * had a line error since the last time we got an
4656059Samurai		 * explicit state index, we have to toss the packet. */
4666059Samurai		if (comp->flags & SLF_TOSS) {
4676059Samurai			INCR(sls_tossed)
4686059Samurai			return (0);
4696059Samurai		}
4706059Samurai	}
4716059Samurai	cs = &comp->rstate[comp->last_recv];
4726059Samurai	hlen = cs->cs_ip.ip_hl << 2;
4736059Samurai	th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
4746059Samurai	th->th_sum = htons((*cp << 8) | cp[1]);
4756059Samurai	cp += 2;
4766059Samurai	if (changes & TCP_PUSH_BIT)
4776059Samurai		th->th_flags |= TH_PUSH;
4786059Samurai	else
4796059Samurai		th->th_flags &=~ TH_PUSH;
4806059Samurai
4816059Samurai	switch (changes & SPECIALS_MASK) {
4826059Samurai	case SPECIAL_I:
4836059Samurai		{
4846059Samurai		register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
4856059Samurai		th->th_ack = htonl(ntohl(th->th_ack) + i);
4866059Samurai		th->th_seq = htonl(ntohl(th->th_seq) + i);
4876059Samurai		}
4886059Samurai		break;
4896059Samurai
4906059Samurai	case SPECIAL_D:
4916059Samurai		th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
4926059Samurai				   - cs->cs_hlen);
4936059Samurai		break;
4946059Samurai
4956059Samurai	default:
4966059Samurai		if (changes & NEW_U) {
4976059Samurai			th->th_flags |= TH_URG;
4986059Samurai			DECODEU(th->th_urp)
4996059Samurai		} else
5006059Samurai			th->th_flags &=~ TH_URG;
5016059Samurai		if (changes & NEW_W)
5026059Samurai			DECODES(th->th_win)
5036059Samurai		if (changes & NEW_A)
5046059Samurai			DECODEL(th->th_ack)
5056059Samurai		if (changes & NEW_S) {
50626516Sbrian			LogPrintf(LogDEBUG, "NEW_S: %02x, %02x, %02x\n",
50726516Sbrian				*cp, cp[1], cp[2]);
5086059Samurai			DECODEL(th->th_seq)
5096059Samurai		}
5106059Samurai		break;
5116059Samurai	}
5126059Samurai	if (changes & NEW_I) {
5136059Samurai		DECODES(cs->cs_ip.ip_id)
5146059Samurai	} else
5156059Samurai		cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
5166059Samurai
51726516Sbrian	LogPrintf(LogDEBUG, "Uncompress: id = %04x, seq = %08x\n",
51826516Sbrian		  cs->cs_ip.ip_id, ntohl(th->th_seq));
51926516Sbrian
5206059Samurai	/*
5216059Samurai	 * At this point, cp points to the first byte of data in the
5226059Samurai	 * packet.  If we're not aligned on a 4-byte boundary, copy the
5236059Samurai	 * data down so the ip & tcp headers will be aligned.  Then back up
5246059Samurai	 * cp by the tcp/ip header length to make room for the reconstructed
5256059Samurai	 * header (we assume the packet we were handed has enough space to
5266059Samurai	 * prepend 128 bytes of header).  Adjust the length to account for
5276059Samurai	 * the new header & fill in the IP total length.
5286059Samurai	 */
5296059Samurai	len -= (cp - *bufp);
5306059Samurai	if (len < 0)
5316059Samurai		/* we must have dropped some characters (crc should detect
5326059Samurai		 * this but the old slip framing won't) */
5336059Samurai		goto bad;
5346059Samurai
5356059Samurai#ifdef notdef
5366059Samurai	if ((int)cp & 3) {
5376059Samurai		if (len > 0)
5386059Samurai			(void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len);
5396059Samurai		cp = (u_char *)((int)cp &~ 3);
5406059Samurai	}
5416059Samurai#endif
5426059Samurai
5436059Samurai	cp -= cs->cs_hlen;
5446059Samurai	len += cs->cs_hlen;
5456059Samurai	cs->cs_ip.ip_len = htons(len);
5466059Samurai	BCOPY(&cs->cs_ip, cp, cs->cs_hlen);
5476059Samurai	*bufp = cp;
5486059Samurai
5496059Samurai	/* recompute the ip header checksum */
5506059Samurai	{
5516059Samurai		register u_short *bp = (u_short *)cp;
5526059Samurai		for (changes = 0; hlen > 0; hlen -= 2)
5536059Samurai			changes += *bp++;
5546059Samurai		changes = (changes & 0xffff) + (changes >> 16);
5556059Samurai		changes = (changes & 0xffff) + (changes >> 16);
5566059Samurai		((struct ip *)cp)->ip_sum = ~ changes;
5576059Samurai	}
5586059Samurai	return (len);
5596059Samuraibad:
5606059Samurai	comp->flags |= SLF_TOSS;
5616059Samurai	INCR(sls_errorin)
5626059Samurai	return (0);
5636059Samurai}
5646059Samurai
5656059Samuraiint
5666059SamuraiReportCompress()
5676059Samurai{
56826516Sbrian  if (!VarTerm)
56926516Sbrian    return 1;
57026516Sbrian
57126516Sbrian  fprintf(VarTerm, "Out:  %d (compress) / %d (total)",
5726059Samurai	slstat.sls_compressed, slstat.sls_packets);
57326516Sbrian  fprintf(VarTerm, "  %d (miss) / %d (search)\n",
5746059Samurai	slstat.sls_misses, slstat.sls_searches);
57526516Sbrian  fprintf(VarTerm, "In:  %d (compress), %d (uncompress)",
5766059Samurai	slstat.sls_compressedin, slstat.sls_uncompressedin);
57726516Sbrian  fprintf(VarTerm, "  %d (error),  %d (tossed)\n",
5786059Samurai	slstat.sls_errorin, slstat.sls_tossed);
57926516Sbrian  return 0;
5806059Samurai}
581