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