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