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