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