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