xref: /titanic_52/usr/src/uts/common/io/ppp/spppcomp/vjcompress.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2000 by Sun Microsystems, Inc.
3*7c478bd9Sstevel@tonic-gate  * All rights reserved.
4*7c478bd9Sstevel@tonic-gate  *
5*7c478bd9Sstevel@tonic-gate  * Routines to compress and uncompess tcp packets (for transmission
6*7c478bd9Sstevel@tonic-gate  * over low speed serial lines.
7*7c478bd9Sstevel@tonic-gate  *
8*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1989 Regents of the University of California.
9*7c478bd9Sstevel@tonic-gate  * All rights reserved.
10*7c478bd9Sstevel@tonic-gate  *
11*7c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
12*7c478bd9Sstevel@tonic-gate  * provided that the above copyright notice and this paragraph are
13*7c478bd9Sstevel@tonic-gate  * duplicated in all such forms and that any documentation,
14*7c478bd9Sstevel@tonic-gate  * advertising materials, and other materials related to such
15*7c478bd9Sstevel@tonic-gate  * distribution and use acknowledge that the software was developed
16*7c478bd9Sstevel@tonic-gate  * by the University of California, Berkeley.  The name of the
17*7c478bd9Sstevel@tonic-gate  * University may not be used to endorse or promote products derived
18*7c478bd9Sstevel@tonic-gate  * from this software without specific prior written permission.
19*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
20*7c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
21*7c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22*7c478bd9Sstevel@tonic-gate  *
23*7c478bd9Sstevel@tonic-gate  *	Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
24*7c478bd9Sstevel@tonic-gate  *	- Initial distribution.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au,
27*7c478bd9Sstevel@tonic-gate  * so that the entire packet being decompressed doesn't have
28*7c478bd9Sstevel@tonic-gate  * to be in contiguous memory (just the compressed header).
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate /*
32*7c478bd9Sstevel@tonic-gate  * This version is used under STREAMS in Solaris 2
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  * $Id: vjcompress.c,v 1.10 1999/09/15 23:49:06 masputra Exp $
35*7c478bd9Sstevel@tonic-gate  */
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>	/* for ntohl, etc. */
40*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
44*7c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
45*7c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
46*7c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate #include <net/ppp_defs.h>
49*7c478bd9Sstevel@tonic-gate #include <net/vjcompress.h>
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate #ifndef VJ_NO_STATS
54*7c478bd9Sstevel@tonic-gate #define	INCR(counter) ++comp->stats.counter
55*7c478bd9Sstevel@tonic-gate #else
56*7c478bd9Sstevel@tonic-gate #define	INCR(counter)
57*7c478bd9Sstevel@tonic-gate #endif
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate #define	BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (unsigned int)(n))
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #undef  BCOPY
62*7c478bd9Sstevel@tonic-gate #define	BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (unsigned int)(n))
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate /*
65*7c478bd9Sstevel@tonic-gate  * I'd like to use offsetof(struct ip,ip_hl) and offsetof(struct
66*7c478bd9Sstevel@tonic-gate  * tcp,th_off), but these are bitfields.
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate #define	getip_hl(bp)	(((uchar_t *)bp)[0] & 0x0F)
69*7c478bd9Sstevel@tonic-gate #define	getth_off(bp)	(((uchar_t *)bp)[12] >> 4)
70*7c478bd9Sstevel@tonic-gate #define	getip_p(bp)	(((uchar_t *)bp)[offsetof(struct ip, ip_p)])
71*7c478bd9Sstevel@tonic-gate #define	setip_p(bp, v)	(((uchar_t *)bp)[offsetof(struct ip, ip_p)] = (v))
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate /*
74*7c478bd9Sstevel@tonic-gate  * vj_compress_init()
75*7c478bd9Sstevel@tonic-gate  */
76*7c478bd9Sstevel@tonic-gate void
77*7c478bd9Sstevel@tonic-gate vj_compress_init(struct vjcompress *comp, int max_state)
78*7c478bd9Sstevel@tonic-gate {
79*7c478bd9Sstevel@tonic-gate 	register uint_t		i;
80*7c478bd9Sstevel@tonic-gate 	register struct cstate	*tstate = comp->tstate;
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate 	if (max_state == -1) {
83*7c478bd9Sstevel@tonic-gate 		max_state = MAX_STATES - 1;
84*7c478bd9Sstevel@tonic-gate 	}
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate 	bzero((char *)comp, sizeof (*comp));
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 	for (i = max_state; i > 0; --i) {
89*7c478bd9Sstevel@tonic-gate 		tstate[i].cs_id = i & 0xff;
90*7c478bd9Sstevel@tonic-gate 		tstate[i].cs_next = &tstate[i - 1];
91*7c478bd9Sstevel@tonic-gate 	}
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	tstate[0].cs_next = &tstate[max_state];
94*7c478bd9Sstevel@tonic-gate 	tstate[0].cs_id = 0;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	comp->last_cs = &tstate[0];
97*7c478bd9Sstevel@tonic-gate 	comp->last_recv = 255;
98*7c478bd9Sstevel@tonic-gate 	comp->last_xmit = 255;
99*7c478bd9Sstevel@tonic-gate 	comp->flags = VJF_TOSS;
100*7c478bd9Sstevel@tonic-gate }
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate /*
103*7c478bd9Sstevel@tonic-gate  * ENCODE encodes a number that is known to be non-zero.  ENCODEZ
104*7c478bd9Sstevel@tonic-gate  * checks for zero (since zero has to be encoded in the long, 3 byte
105*7c478bd9Sstevel@tonic-gate  * form).
106*7c478bd9Sstevel@tonic-gate  */
107*7c478bd9Sstevel@tonic-gate #define	ENCODE(n) {						\
108*7c478bd9Sstevel@tonic-gate 	if ((ushort_t)(n) >= 256) {				\
109*7c478bd9Sstevel@tonic-gate 		*cp++ = 0;					\
110*7c478bd9Sstevel@tonic-gate 		cp[1] = (n) & 0xff;				\
111*7c478bd9Sstevel@tonic-gate 		cp[0] = ((n) >> 8) & 0xff;			\
112*7c478bd9Sstevel@tonic-gate 		cp += 2;					\
113*7c478bd9Sstevel@tonic-gate 	} else {						\
114*7c478bd9Sstevel@tonic-gate 		*cp++ = (n) & 0xff;				\
115*7c478bd9Sstevel@tonic-gate 	}							\
116*7c478bd9Sstevel@tonic-gate }
117*7c478bd9Sstevel@tonic-gate #define	ENCODEZ(n) {						\
118*7c478bd9Sstevel@tonic-gate 	if ((ushort_t)(n) >= 256 || (ushort_t)(n) == 0) {	\
119*7c478bd9Sstevel@tonic-gate 		*cp++ = 0;					\
120*7c478bd9Sstevel@tonic-gate 		cp[1] = (n) & 0xff;				\
121*7c478bd9Sstevel@tonic-gate 		cp[0] = ((n) >> 8) & 0xff;			\
122*7c478bd9Sstevel@tonic-gate 		cp += 2;					\
123*7c478bd9Sstevel@tonic-gate 	} else {						\
124*7c478bd9Sstevel@tonic-gate 		*cp++ = (n) & 0xff;				\
125*7c478bd9Sstevel@tonic-gate 	}							\
126*7c478bd9Sstevel@tonic-gate }
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate #define	DECODEL(f) {							\
129*7c478bd9Sstevel@tonic-gate 	if (*cp == 0) {							\
130*7c478bd9Sstevel@tonic-gate 		uint32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]);	\
131*7c478bd9Sstevel@tonic-gate 		(f) = htonl(tmp);					\
132*7c478bd9Sstevel@tonic-gate 		cp += 3;						\
133*7c478bd9Sstevel@tonic-gate 	} else {							\
134*7c478bd9Sstevel@tonic-gate 		uint32_t tmp = ntohl(f) + (uint32_t)*cp++;		\
135*7c478bd9Sstevel@tonic-gate 		(f) = htonl(tmp);					\
136*7c478bd9Sstevel@tonic-gate 	}								\
137*7c478bd9Sstevel@tonic-gate }
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate #define	DECODES(f) {							\
140*7c478bd9Sstevel@tonic-gate 	if (*cp == 0) {							\
141*7c478bd9Sstevel@tonic-gate 		ushort_t tmp = ntohs(f) + ((cp[1] << 8) | cp[2]);	\
142*7c478bd9Sstevel@tonic-gate 		(f) = htons(tmp);					\
143*7c478bd9Sstevel@tonic-gate 		cp += 3;						\
144*7c478bd9Sstevel@tonic-gate 	} else {							\
145*7c478bd9Sstevel@tonic-gate 		ushort_t tmp = ntohs(f) + (uint32_t)*cp++;		\
146*7c478bd9Sstevel@tonic-gate 		(f) = htons(tmp);					\
147*7c478bd9Sstevel@tonic-gate 	}								\
148*7c478bd9Sstevel@tonic-gate }
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate #define	DECODEU(f) {							\
151*7c478bd9Sstevel@tonic-gate 	if (*cp == 0) {							\
152*7c478bd9Sstevel@tonic-gate 		(f) = htons((cp[1] << 8) | cp[2]);			\
153*7c478bd9Sstevel@tonic-gate 		cp += 3;						\
154*7c478bd9Sstevel@tonic-gate 	} else {							\
155*7c478bd9Sstevel@tonic-gate 		(f) = htons((uint32_t)*cp++);				\
156*7c478bd9Sstevel@tonic-gate 	}								\
157*7c478bd9Sstevel@tonic-gate }
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate uint_t
160*7c478bd9Sstevel@tonic-gate vj_compress_tcp(register struct ip *ip, uint_t mlen, struct vjcompress *comp,
161*7c478bd9Sstevel@tonic-gate 	int compress_cid, uchar_t **vjhdrp)
162*7c478bd9Sstevel@tonic-gate {
163*7c478bd9Sstevel@tonic-gate 	register struct cstate	*cs = comp->last_cs->cs_next;
164*7c478bd9Sstevel@tonic-gate 	register uint_t		hlen = getip_hl(ip);
165*7c478bd9Sstevel@tonic-gate 	register struct tcphdr	*oth;
166*7c478bd9Sstevel@tonic-gate 	register struct tcphdr	*th;
167*7c478bd9Sstevel@tonic-gate 	register uint_t		deltaS;
168*7c478bd9Sstevel@tonic-gate 	register uint_t		deltaA;
169*7c478bd9Sstevel@tonic-gate 	register uint_t		changes = 0;
170*7c478bd9Sstevel@tonic-gate 	uchar_t			new_seq[16];
171*7c478bd9Sstevel@tonic-gate 	register uchar_t	*cp = new_seq;
172*7c478bd9Sstevel@tonic-gate 	register uint_t		thlen;
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	/*
175*7c478bd9Sstevel@tonic-gate 	 * Bail if this is an IP fragment or if the TCP packet isn't
176*7c478bd9Sstevel@tonic-gate 	 * `compressible' (i.e., ACK isn't set or some other control bit is
177*7c478bd9Sstevel@tonic-gate 	 * set).  (We assume that the caller has already made sure the
178*7c478bd9Sstevel@tonic-gate 	 * packet is IP proto TCP)
179*7c478bd9Sstevel@tonic-gate 	 */
180*7c478bd9Sstevel@tonic-gate 	if ((ip->ip_off & htons(0x3fff)) || mlen < 40) {
181*7c478bd9Sstevel@tonic-gate 		return (TYPE_IP);
182*7c478bd9Sstevel@tonic-gate 	}
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	th = (struct tcphdr *)&((int *)ip)[hlen];
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) {
187*7c478bd9Sstevel@tonic-gate 		return (TYPE_IP);
188*7c478bd9Sstevel@tonic-gate 	}
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	thlen = (hlen + getth_off(th)) << 2;
191*7c478bd9Sstevel@tonic-gate 	if (thlen > mlen) {
192*7c478bd9Sstevel@tonic-gate 		return (TYPE_IP);
193*7c478bd9Sstevel@tonic-gate 	}
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	/*
196*7c478bd9Sstevel@tonic-gate 	 * Packet is compressible -- we're going to send either a
197*7c478bd9Sstevel@tonic-gate 	 * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
198*7c478bd9Sstevel@tonic-gate 	 * to locate (or create) the connection state.  Special case the
199*7c478bd9Sstevel@tonic-gate 	 * most recently used connection since it's most likely to be used
200*7c478bd9Sstevel@tonic-gate 	 * again & we don't have to do any reordering if it's used.
201*7c478bd9Sstevel@tonic-gate 	 */
202*7c478bd9Sstevel@tonic-gate 	INCR(vjs_packets);
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
205*7c478bd9Sstevel@tonic-gate 		ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
206*7c478bd9Sstevel@tonic-gate 		*(int *)th != ((int *)&cs->cs_ip)[getip_hl(&cs->cs_ip)]) {
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 		/*
209*7c478bd9Sstevel@tonic-gate 		 * Wasn't the first -- search for it.
210*7c478bd9Sstevel@tonic-gate 		 *
211*7c478bd9Sstevel@tonic-gate 		 * States are kept in a circularly linked list with
212*7c478bd9Sstevel@tonic-gate 		 * last_cs pointing to the end of the list.  The
213*7c478bd9Sstevel@tonic-gate 		 * list is kept in lru order by moving a state to the
214*7c478bd9Sstevel@tonic-gate 		 * head of the list whenever it is referenced.  Since
215*7c478bd9Sstevel@tonic-gate 		 * the list is short and, empirically, the connection
216*7c478bd9Sstevel@tonic-gate 		 * we want is almost always near the front, we locate
217*7c478bd9Sstevel@tonic-gate 		 * states via linear search.  If we don't find a state
218*7c478bd9Sstevel@tonic-gate 		 * for the datagram, the oldest state is (re-)used.
219*7c478bd9Sstevel@tonic-gate 		 */
220*7c478bd9Sstevel@tonic-gate 		register struct cstate	*lcs;
221*7c478bd9Sstevel@tonic-gate 		register struct cstate	*lastcs = comp->last_cs;
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 		do {
224*7c478bd9Sstevel@tonic-gate 			lcs = cs; cs = cs->cs_next;
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 			INCR(vjs_searches);
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 			if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr &&
229*7c478bd9Sstevel@tonic-gate 				ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr &&
230*7c478bd9Sstevel@tonic-gate 				*(int *)th == ((int *)
231*7c478bd9Sstevel@tonic-gate 					&cs->cs_ip)[getip_hl(&cs->cs_ip)]) {
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 				goto found;
234*7c478bd9Sstevel@tonic-gate 			}
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 		} while (cs != lastcs);
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 		/*
239*7c478bd9Sstevel@tonic-gate 		 * Didn't find it -- re-use oldest cstate.  Send an
240*7c478bd9Sstevel@tonic-gate 		 * uncompressed packet that tells the other side what
241*7c478bd9Sstevel@tonic-gate 		 * connection number we're using for this conversation.
242*7c478bd9Sstevel@tonic-gate 		 * Note that since the state list is circular, the oldest
243*7c478bd9Sstevel@tonic-gate 		 * state points to the newest and we only need to set
244*7c478bd9Sstevel@tonic-gate 		 * last_cs to update the lru linkage.
245*7c478bd9Sstevel@tonic-gate 		 */
246*7c478bd9Sstevel@tonic-gate 		INCR(vjs_misses);
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 		comp->last_cs = lcs;
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 		goto uncompressed;
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate found:
253*7c478bd9Sstevel@tonic-gate 		/*
254*7c478bd9Sstevel@tonic-gate 		 * Found it -- move to the front on the connection list.
255*7c478bd9Sstevel@tonic-gate 		 */
256*7c478bd9Sstevel@tonic-gate 		if (cs == lastcs) {
257*7c478bd9Sstevel@tonic-gate 			comp->last_cs = lcs;
258*7c478bd9Sstevel@tonic-gate 		} else {
259*7c478bd9Sstevel@tonic-gate 			lcs->cs_next = cs->cs_next;
260*7c478bd9Sstevel@tonic-gate 			cs->cs_next = lastcs->cs_next;
261*7c478bd9Sstevel@tonic-gate 			lastcs->cs_next = cs;
262*7c478bd9Sstevel@tonic-gate 		}
263*7c478bd9Sstevel@tonic-gate 	}
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	/*
266*7c478bd9Sstevel@tonic-gate 	 * Make sure that only what we expect to change changed. The first
267*7c478bd9Sstevel@tonic-gate 	 * line of the `if' checks the IP protocol version, header length &
268*7c478bd9Sstevel@tonic-gate 	 * type of service.  The 2nd line checks the "Don't fragment" bit.
269*7c478bd9Sstevel@tonic-gate 	 * The 3rd line checks the time-to-live and protocol (the protocol
270*7c478bd9Sstevel@tonic-gate 	 * check is unnecessary but costless).  The 4th line checks the TCP
271*7c478bd9Sstevel@tonic-gate 	 * header length.  The 5th line checks IP options, if any.  The 6th
272*7c478bd9Sstevel@tonic-gate 	 * line checks TCP options, if any.  If any of these things are
273*7c478bd9Sstevel@tonic-gate 	 * different between the previous & current datagram, we send the
274*7c478bd9Sstevel@tonic-gate 	 * current datagram `uncompressed'.
275*7c478bd9Sstevel@tonic-gate 	 */
276*7c478bd9Sstevel@tonic-gate 	oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen];
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	/* Used to check for IP options. */
279*7c478bd9Sstevel@tonic-gate 	deltaS = hlen;
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	if (((ushort_t *)ip)[0] != ((ushort_t *)&cs->cs_ip)[0] ||
282*7c478bd9Sstevel@tonic-gate 		((ushort_t *)ip)[3] != ((ushort_t *)&cs->cs_ip)[3] ||
283*7c478bd9Sstevel@tonic-gate 		((ushort_t *)ip)[4] != ((ushort_t *)&cs->cs_ip)[4] ||
284*7c478bd9Sstevel@tonic-gate 		getth_off(th) != getth_off(oth) ||
285*7c478bd9Sstevel@tonic-gate 		(deltaS > 5 &&
286*7c478bd9Sstevel@tonic-gate 			BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
287*7c478bd9Sstevel@tonic-gate 		(getth_off(th) > 5 &&
288*7c478bd9Sstevel@tonic-gate 			BCMP(th + 1, oth + 1, (getth_off(th) - 5) << 2))) {
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 		goto uncompressed;
291*7c478bd9Sstevel@tonic-gate 	}
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 	/*
294*7c478bd9Sstevel@tonic-gate 	 * Figure out which of the changing fields changed.  The
295*7c478bd9Sstevel@tonic-gate 	 * receiver expects changes in the order: urgent, window,
296*7c478bd9Sstevel@tonic-gate 	 * ack, seq (the order minimizes the number of temporaries
297*7c478bd9Sstevel@tonic-gate 	 * needed in this section of code).
298*7c478bd9Sstevel@tonic-gate 	 */
299*7c478bd9Sstevel@tonic-gate 	if (th->th_flags & TH_URG) {
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 		deltaS = ntohs(th->th_urp);
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 		ENCODEZ(deltaS);
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 		changes |= NEW_U;
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	} else if (th->th_urp != oth->th_urp) {
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 		/*
310*7c478bd9Sstevel@tonic-gate 		 * argh! URG not set but urp changed -- a sensible
311*7c478bd9Sstevel@tonic-gate 		 * implementation should never do this but RFC793
312*7c478bd9Sstevel@tonic-gate 		 * doesn't prohibit the change so we have to deal
313*7c478bd9Sstevel@tonic-gate 		 * with it
314*7c478bd9Sstevel@tonic-gate 		 */
315*7c478bd9Sstevel@tonic-gate 		goto uncompressed;
316*7c478bd9Sstevel@tonic-gate 	}
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	if ((deltaS = (ushort_t)(ntohs(th->th_win) - ntohs(oth->th_win))) > 0) {
319*7c478bd9Sstevel@tonic-gate 		ENCODE(deltaS);
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 		changes |= NEW_W;
322*7c478bd9Sstevel@tonic-gate 	}
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 	if ((deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) > 0) {
325*7c478bd9Sstevel@tonic-gate 		if (deltaA > 0xffff) {
326*7c478bd9Sstevel@tonic-gate 			goto uncompressed;
327*7c478bd9Sstevel@tonic-gate 		}
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 		ENCODE(deltaA);
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 		changes |= NEW_A;
332*7c478bd9Sstevel@tonic-gate 	}
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	if ((deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) > 0) {
335*7c478bd9Sstevel@tonic-gate 		if (deltaS > 0xffff) {
336*7c478bd9Sstevel@tonic-gate 			goto uncompressed;
337*7c478bd9Sstevel@tonic-gate 		}
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 		ENCODE(deltaS);
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 		changes |= NEW_S;
342*7c478bd9Sstevel@tonic-gate 	}
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	switch (changes) {
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	case 0:
347*7c478bd9Sstevel@tonic-gate 		/*
348*7c478bd9Sstevel@tonic-gate 		 * Nothing changed. If this packet contains data and the
349*7c478bd9Sstevel@tonic-gate 		 * last one didn't, this is probably a data packet following
350*7c478bd9Sstevel@tonic-gate 		 * an ack (normal on an interactive connection) and we send
351*7c478bd9Sstevel@tonic-gate 		 * it compressed.  Otherwise it's probably a retransmit,
352*7c478bd9Sstevel@tonic-gate 		 * retransmitted ack or window probe.  Send it uncompressed
353*7c478bd9Sstevel@tonic-gate 		 * in case the other side missed the compressed version.
354*7c478bd9Sstevel@tonic-gate 		 */
355*7c478bd9Sstevel@tonic-gate 		if (ip->ip_len != cs->cs_ip.ip_len &&
356*7c478bd9Sstevel@tonic-gate 					ntohs(cs->cs_ip.ip_len) == thlen) {
357*7c478bd9Sstevel@tonic-gate 			break;
358*7c478bd9Sstevel@tonic-gate 		}
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 		/* (otherwise fall through) */
361*7c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 	case SPECIAL_I:
364*7c478bd9Sstevel@tonic-gate 	case SPECIAL_D:
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 		/*
367*7c478bd9Sstevel@tonic-gate 		 * actual changes match one of our special case encodings --
368*7c478bd9Sstevel@tonic-gate 		 * send packet uncompressed.
369*7c478bd9Sstevel@tonic-gate 		 */
370*7c478bd9Sstevel@tonic-gate 		goto uncompressed;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	case NEW_S|NEW_A:
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 		if (deltaS == deltaA &&
375*7c478bd9Sstevel@tonic-gate 				deltaS == ntohs(cs->cs_ip.ip_len) - thlen) {
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 			/*
378*7c478bd9Sstevel@tonic-gate 			 * special case for echoed terminal traffic
379*7c478bd9Sstevel@tonic-gate 			 */
380*7c478bd9Sstevel@tonic-gate 			changes = SPECIAL_I;
381*7c478bd9Sstevel@tonic-gate 			cp = new_seq;
382*7c478bd9Sstevel@tonic-gate 		}
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 		break;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	case NEW_S:
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 		if (deltaS == ntohs(cs->cs_ip.ip_len) - thlen) {
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 			/*
391*7c478bd9Sstevel@tonic-gate 			 * special case for data xfer
392*7c478bd9Sstevel@tonic-gate 			 */
393*7c478bd9Sstevel@tonic-gate 			changes = SPECIAL_D;
394*7c478bd9Sstevel@tonic-gate 			cp = new_seq;
395*7c478bd9Sstevel@tonic-gate 		}
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 		break;
398*7c478bd9Sstevel@tonic-gate 	}
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
401*7c478bd9Sstevel@tonic-gate 	if (deltaS != 1) {
402*7c478bd9Sstevel@tonic-gate 		ENCODEZ(deltaS);
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 		changes |= NEW_I;
405*7c478bd9Sstevel@tonic-gate 	}
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	if (th->th_flags & TH_PUSH) {
408*7c478bd9Sstevel@tonic-gate 		changes |= TCP_PUSH_BIT;
409*7c478bd9Sstevel@tonic-gate 	}
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	/*
412*7c478bd9Sstevel@tonic-gate 	 * Grab the cksum before we overwrite it below.  Then update our
413*7c478bd9Sstevel@tonic-gate 	 * state with this packet's header.
414*7c478bd9Sstevel@tonic-gate 	 */
415*7c478bd9Sstevel@tonic-gate 	deltaA = ntohs(th->th_sum);
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	BCOPY(ip, &cs->cs_ip, thlen);
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	/*
420*7c478bd9Sstevel@tonic-gate 	 * We want to use the original packet as our compressed packet.
421*7c478bd9Sstevel@tonic-gate 	 * (cp - new_seq) is the number of bytes we need for compressed
422*7c478bd9Sstevel@tonic-gate 	 * sequence numbers.  In addition we need one byte for the change
423*7c478bd9Sstevel@tonic-gate 	 * mask, one for the connection id and two for the tcp checksum.
424*7c478bd9Sstevel@tonic-gate 	 * So, (cp - new_seq) + 4 bytes of header are needed.  thlen is how
425*7c478bd9Sstevel@tonic-gate 	 * many bytes of the original packet to toss so subtract the two to
426*7c478bd9Sstevel@tonic-gate 	 * get the new packet size.
427*7c478bd9Sstevel@tonic-gate 	 */
428*7c478bd9Sstevel@tonic-gate 	deltaS = cp - new_seq;
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	cp = (uchar_t *)ip;
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
433*7c478bd9Sstevel@tonic-gate 		comp->last_xmit = cs->cs_id;
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 		thlen -= deltaS + 4;
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 		*vjhdrp = (cp += thlen);
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 		*cp++ = changes | NEW_C;
440*7c478bd9Sstevel@tonic-gate 		*cp++ = cs->cs_id;
441*7c478bd9Sstevel@tonic-gate 	} else {
442*7c478bd9Sstevel@tonic-gate 		thlen -= deltaS + 3;
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 		*vjhdrp = (cp += thlen);
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 		*cp++ = changes & 0xff;
447*7c478bd9Sstevel@tonic-gate 	}
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	*cp++ = (deltaA >> 8) & 0xff;
450*7c478bd9Sstevel@tonic-gate 	*cp++ = deltaA & 0xff;
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 	BCOPY(new_seq, cp, deltaS);
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	INCR(vjs_compressed);
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	return (TYPE_COMPRESSED_TCP);
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	/*
459*7c478bd9Sstevel@tonic-gate 	 * Update connection state cs & send uncompressed packet (that is,
460*7c478bd9Sstevel@tonic-gate 	 * a regular ip/tcp packet but with the 'conversation id' we hope
461*7c478bd9Sstevel@tonic-gate 	 * to use on future compressed packets in the protocol field).
462*7c478bd9Sstevel@tonic-gate 	 */
463*7c478bd9Sstevel@tonic-gate uncompressed:
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	BCOPY(ip, &cs->cs_ip, thlen);
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	ip->ip_p = cs->cs_id;
468*7c478bd9Sstevel@tonic-gate 	comp->last_xmit = cs->cs_id;
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	return (TYPE_UNCOMPRESSED_TCP);
471*7c478bd9Sstevel@tonic-gate }
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate /*
474*7c478bd9Sstevel@tonic-gate  * vj_uncompress_err()
475*7c478bd9Sstevel@tonic-gate  *
476*7c478bd9Sstevel@tonic-gate  * Called when we may have missed a packet.
477*7c478bd9Sstevel@tonic-gate  */
478*7c478bd9Sstevel@tonic-gate void
479*7c478bd9Sstevel@tonic-gate vj_uncompress_err(struct vjcompress *comp)
480*7c478bd9Sstevel@tonic-gate {
481*7c478bd9Sstevel@tonic-gate 	comp->flags |= VJF_TOSS;
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	INCR(vjs_errorin);
484*7c478bd9Sstevel@tonic-gate }
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate /*
487*7c478bd9Sstevel@tonic-gate  * vj_uncompress_uncomp()
488*7c478bd9Sstevel@tonic-gate  *
489*7c478bd9Sstevel@tonic-gate  * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP.
490*7c478bd9Sstevel@tonic-gate  */
491*7c478bd9Sstevel@tonic-gate int
492*7c478bd9Sstevel@tonic-gate vj_uncompress_uncomp(uchar_t *buf, int buflen, struct vjcompress *comp)
493*7c478bd9Sstevel@tonic-gate {
494*7c478bd9Sstevel@tonic-gate 	register uint_t		hlen;
495*7c478bd9Sstevel@tonic-gate 	register struct cstate	*cs;
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 	hlen = getip_hl(buf) << 2;
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	if (getip_p(buf) >= MAX_STATES ||
500*7c478bd9Sstevel@tonic-gate 	    hlen + sizeof (struct tcphdr) > buflen ||
501*7c478bd9Sstevel@tonic-gate 	    (hlen += getth_off(buf+hlen) << 2) > buflen || hlen > MAX_HDR) {
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 		comp->flags |= VJF_TOSS;
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 		INCR(vjs_errorin);
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 		return (0);
508*7c478bd9Sstevel@tonic-gate 	}
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	cs = &comp->rstate[comp->last_recv = getip_p(buf)];
511*7c478bd9Sstevel@tonic-gate 	comp->flags &= ~VJF_TOSS;
512*7c478bd9Sstevel@tonic-gate 	setip_p(buf, IPPROTO_TCP);
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	BCOPY(buf, &cs->cs_ip, hlen);
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	cs->cs_hlen = hlen & 0xff;
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	INCR(vjs_uncompressedin);
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	return (1);
521*7c478bd9Sstevel@tonic-gate }
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate /*
524*7c478bd9Sstevel@tonic-gate  * vj_uncompress_tcp()
525*7c478bd9Sstevel@tonic-gate  *
526*7c478bd9Sstevel@tonic-gate  * Uncompress a packet of type TYPE_COMPRESSED_TCP.
527*7c478bd9Sstevel@tonic-gate  * The packet starts at buf and is of total length total_len.
528*7c478bd9Sstevel@tonic-gate  * The first buflen bytes are at buf; this must include the entire
529*7c478bd9Sstevel@tonic-gate  * compressed TCP/IP header.  This procedure returns the length
530*7c478bd9Sstevel@tonic-gate  * of the VJ header, with a pointer to the uncompressed IP header
531*7c478bd9Sstevel@tonic-gate  * in *hdrp and its length in *hlenp.
532*7c478bd9Sstevel@tonic-gate  */
533*7c478bd9Sstevel@tonic-gate int
534*7c478bd9Sstevel@tonic-gate vj_uncompress_tcp(uchar_t *buf, int buflen, int total_len,
535*7c478bd9Sstevel@tonic-gate 	struct vjcompress *comp, uchar_t **hdrp, uint_t *hlenp)
536*7c478bd9Sstevel@tonic-gate {
537*7c478bd9Sstevel@tonic-gate 	register uchar_t	*cp;
538*7c478bd9Sstevel@tonic-gate 	register uint_t		hlen;
539*7c478bd9Sstevel@tonic-gate 	register uint_t		changes;
540*7c478bd9Sstevel@tonic-gate 	register struct tcphdr	*th;
541*7c478bd9Sstevel@tonic-gate 	register struct cstate	*cs;
542*7c478bd9Sstevel@tonic-gate 	register ushort_t	*bp;
543*7c478bd9Sstevel@tonic-gate 	register uint_t		vjlen;
544*7c478bd9Sstevel@tonic-gate 	register uint32_t	tmp;
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 	INCR(vjs_compressedin);
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	cp = buf;
549*7c478bd9Sstevel@tonic-gate 	changes = *cp++;
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 	if (changes & NEW_C) {
552*7c478bd9Sstevel@tonic-gate 		/*
553*7c478bd9Sstevel@tonic-gate 		 * Make sure the state index is in range, then grab the state.
554*7c478bd9Sstevel@tonic-gate 		 * If we have a good state index, clear the 'discard' flag.
555*7c478bd9Sstevel@tonic-gate 		 */
556*7c478bd9Sstevel@tonic-gate 		if (*cp >= MAX_STATES) {
557*7c478bd9Sstevel@tonic-gate 			goto bad;
558*7c478bd9Sstevel@tonic-gate 		}
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 		comp->flags &= ~VJF_TOSS;
561*7c478bd9Sstevel@tonic-gate 		comp->last_recv = *cp++;
562*7c478bd9Sstevel@tonic-gate 	} else {
563*7c478bd9Sstevel@tonic-gate 		/*
564*7c478bd9Sstevel@tonic-gate 		 * this packet has an implicit state index.  If we've
565*7c478bd9Sstevel@tonic-gate 		 * had a line error since the last time we got an
566*7c478bd9Sstevel@tonic-gate 		 * explicit state index, we have to toss the packet
567*7c478bd9Sstevel@tonic-gate 		 */
568*7c478bd9Sstevel@tonic-gate 		if (comp->flags & VJF_TOSS) {
569*7c478bd9Sstevel@tonic-gate 			INCR(vjs_tossed);
570*7c478bd9Sstevel@tonic-gate 			return (-1);
571*7c478bd9Sstevel@tonic-gate 		}
572*7c478bd9Sstevel@tonic-gate 	}
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate 	cs = &comp->rstate[comp->last_recv];
575*7c478bd9Sstevel@tonic-gate 	hlen = getip_hl(&cs->cs_ip) << 2;
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	th = (struct tcphdr *)((uint32_t *)&cs->cs_ip+hlen/sizeof (uint32_t));
578*7c478bd9Sstevel@tonic-gate 	th->th_sum = htons((*cp << 8) | cp[1]);
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 	cp += 2;
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	if (changes & TCP_PUSH_BIT) {
583*7c478bd9Sstevel@tonic-gate 		th->th_flags |= TH_PUSH;
584*7c478bd9Sstevel@tonic-gate 	} else {
585*7c478bd9Sstevel@tonic-gate 		th->th_flags &= ~TH_PUSH;
586*7c478bd9Sstevel@tonic-gate 	}
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	switch (changes & SPECIALS_MASK) {
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	case SPECIAL_I:
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 		{
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 		register uint32_t	i;
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 		i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 		tmp = ntohl(th->th_ack) + i;
599*7c478bd9Sstevel@tonic-gate 		th->th_ack = htonl(tmp);
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 		tmp = ntohl(th->th_seq) + i;
602*7c478bd9Sstevel@tonic-gate 		th->th_seq = htonl(tmp);
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 		}
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 		break;
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	case SPECIAL_D:
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 		tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
611*7c478bd9Sstevel@tonic-gate 		th->th_seq = htonl(tmp);
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 		break;
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	default:
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 		if (changes & NEW_U) {
618*7c478bd9Sstevel@tonic-gate 			th->th_flags |= TH_URG;
619*7c478bd9Sstevel@tonic-gate 			DECODEU(th->th_urp);
620*7c478bd9Sstevel@tonic-gate 		} else {
621*7c478bd9Sstevel@tonic-gate 			th->th_flags &= ~TH_URG;
622*7c478bd9Sstevel@tonic-gate 		}
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 		if (changes & NEW_W) {
625*7c478bd9Sstevel@tonic-gate 			DECODES(th->th_win);
626*7c478bd9Sstevel@tonic-gate 		}
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 		if (changes & NEW_A) {
629*7c478bd9Sstevel@tonic-gate 			DECODEL(th->th_ack);
630*7c478bd9Sstevel@tonic-gate 		}
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 		if (changes & NEW_S) {
633*7c478bd9Sstevel@tonic-gate 			DECODEL(th->th_seq);
634*7c478bd9Sstevel@tonic-gate 		}
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 		break;
637*7c478bd9Sstevel@tonic-gate 	}
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	if (changes & NEW_I) {
640*7c478bd9Sstevel@tonic-gate 		DECODES(cs->cs_ip.ip_id);
641*7c478bd9Sstevel@tonic-gate 	} else {
642*7c478bd9Sstevel@tonic-gate 		cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1;
643*7c478bd9Sstevel@tonic-gate 		cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id);
644*7c478bd9Sstevel@tonic-gate 	}
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 	/*
647*7c478bd9Sstevel@tonic-gate 	 * At this point, cp points to the first byte of data in the
648*7c478bd9Sstevel@tonic-gate 	 * packet.  Fill in the IP total length and update the IP
649*7c478bd9Sstevel@tonic-gate 	 * header checksum.
650*7c478bd9Sstevel@tonic-gate 	 */
651*7c478bd9Sstevel@tonic-gate 	vjlen = cp - buf;
652*7c478bd9Sstevel@tonic-gate 	buflen -= vjlen;
653*7c478bd9Sstevel@tonic-gate 	if (buflen < 0) {
654*7c478bd9Sstevel@tonic-gate 		/*
655*7c478bd9Sstevel@tonic-gate 		 * we must have dropped some characters (crc should detect
656*7c478bd9Sstevel@tonic-gate 		 * this but the old slip framing won't)
657*7c478bd9Sstevel@tonic-gate 		 */
658*7c478bd9Sstevel@tonic-gate 		goto bad;
659*7c478bd9Sstevel@tonic-gate 	}
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 	total_len += cs->cs_hlen - vjlen;
662*7c478bd9Sstevel@tonic-gate 	cs->cs_ip.ip_len = htons(total_len);
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	/*
665*7c478bd9Sstevel@tonic-gate 	 * recompute the ip header checksum
666*7c478bd9Sstevel@tonic-gate 	 */
667*7c478bd9Sstevel@tonic-gate 	bp = (ushort_t *)&cs->cs_ip;
668*7c478bd9Sstevel@tonic-gate 	cs->cs_ip.ip_sum = 0;
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 	for (changes = 0; hlen > 0; hlen -= 2) {
671*7c478bd9Sstevel@tonic-gate 		changes += *bp++;
672*7c478bd9Sstevel@tonic-gate 	}
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 	changes = (changes & 0xffff) + (changes >> 16);
675*7c478bd9Sstevel@tonic-gate 	changes = (changes & 0xffff) + (changes >> 16);
676*7c478bd9Sstevel@tonic-gate 	cs->cs_ip.ip_sum = ~ changes;
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 	*hdrp = (uchar_t *)&cs->cs_ip;
679*7c478bd9Sstevel@tonic-gate 	*hlenp = cs->cs_hlen;
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 	return (vjlen);
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate bad:
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate 	comp->flags |= VJF_TOSS;
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 	INCR(vjs_errorin);
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate 	return (-1);
690*7c478bd9Sstevel@tonic-gate }
691