36 |
Modified by Jean-Charles Salzeber <jc@varspool.net> |
Modified by Jean-Charles Salzeber <jc@varspool.net> |
37 |
to fit pengfork needs |
to fit pengfork needs |
38 |
*/ |
*/ |
39 |
|
#include <string.h> |
40 |
#include <sys/types.h> |
#include <sys/types.h> |
41 |
#include <sys/param.h> |
#include <sys/param.h> |
42 |
|
|
43 |
#ifdef SVR4 |
#ifdef SVR4 |
44 |
#ifndef __GNUC__ |
#ifndef __GNUC__ |
45 |
#include <sys/byteorder.h> /* for ntohl, etc. */ |
#include <sys/byteorder.h> /* for ntohl, etc. */ |
46 |
#else |
#else |
47 |
/* make sure we don't get the gnu "fixed" one! */ |
/* make sure we don't get the gnu "fixed" one! */ |
48 |
#include "/usr/include/sys/byteorder.h" |
#include "/usr/include/sys/byteorder.h" |
56 |
|
|
57 |
#ifdef AIX4 |
#ifdef AIX4 |
58 |
#define _NETINET_IN_SYSTM_H_ |
#define _NETINET_IN_SYSTM_H_ |
59 |
typedef u_long n_long; |
typedef u_long n_long; |
60 |
#else |
#else |
61 |
#include <netinet/in_systm.h> |
#include <netinet/in_systm.h> |
62 |
#endif |
#endif |
90 |
#endif |
#endif |
91 |
|
|
92 |
void |
void |
93 |
vj_compress_init(comp, max_state) |
vj_compress_init (comp, max_state) |
94 |
struct vjcompress *comp; |
struct vjcompress *comp; |
95 |
int max_state; |
int max_state; |
96 |
{ |
{ |
97 |
register u_int i; |
register u_int i; |
98 |
register struct cstate *tstate = comp->tstate; |
register struct cstate *tstate = comp->tstate; |
99 |
|
|
100 |
if (max_state == -1) |
if (max_state == -1) |
101 |
max_state = MAX_STATES - 1; |
max_state = MAX_STATES - 1; |
102 |
bzero((char *)comp, sizeof(*comp)); |
bzero ((char *) comp, sizeof (*comp)); |
103 |
for (i = max_state; i > 0; --i) { |
for (i = max_state; i > 0; --i) |
104 |
tstate[i].cs_id = i; |
{ |
105 |
tstate[i].cs_next = &tstate[i - 1]; |
tstate[i].cs_id = i; |
106 |
} |
tstate[i].cs_next = &tstate[i - 1]; |
107 |
tstate[0].cs_next = &tstate[max_state]; |
} |
108 |
tstate[0].cs_id = 0; |
tstate[0].cs_next = &tstate[max_state]; |
109 |
comp->last_cs = &tstate[0]; |
tstate[0].cs_id = 0; |
110 |
comp->last_recv = 255; |
comp->last_cs = &tstate[0]; |
111 |
comp->last_xmit = 255; |
comp->last_recv = 255; |
112 |
comp->flags = VJF_TOSS; |
comp->last_xmit = 255; |
113 |
|
comp->flags = VJF_TOSS; |
114 |
} |
} |
115 |
|
|
116 |
|
|
171 |
} |
} |
172 |
|
|
173 |
u_int |
u_int |
174 |
vj_compress_tcp(ip, mlen, comp, compress_cid, vjhdrp) |
vj_compress_tcp (ip, mlen, comp, compress_cid, vjhdrp) |
175 |
register struct ip *ip; |
register struct ip *ip; |
176 |
u_int mlen; |
u_int mlen; |
177 |
struct vjcompress *comp; |
struct vjcompress *comp; |
178 |
int compress_cid; |
int compress_cid; |
179 |
u_char **vjhdrp; |
u_char **vjhdrp; |
180 |
{ |
{ |
181 |
register struct cstate *cs = comp->last_cs->cs_next; |
register struct cstate *cs = comp->last_cs->cs_next; |
182 |
register u_int hlen = getip_hl(*ip); |
register u_int hlen = getip_hl (*ip); |
183 |
register struct tcphdr *oth; |
register struct tcphdr *oth; |
184 |
register struct tcphdr *th; |
register struct tcphdr *th; |
185 |
register u_int deltaS, deltaA; |
register u_int deltaS, deltaA; |
186 |
register u_int changes = 0; |
register u_int changes = 0; |
187 |
u_char new_seq[16]; |
u_char new_seq[16]; |
188 |
register u_char *cp = new_seq; |
register u_char *cp = new_seq; |
189 |
|
|
190 |
/* |
/* |
191 |
* Bail if this is an IP fragment or if the TCP packet isn't |
* Bail if this is an IP fragment or if the TCP packet isn't |
192 |
* `compressible' (i.e., ACK isn't set or some other control bit is |
* `compressible' (i.e., ACK isn't set or some other control bit is |
193 |
* set). (We assume that the caller has already made sure the |
* set). (We assume that the caller has already made sure the |
194 |
* packet is IP proto TCP). |
* packet is IP proto TCP). |
195 |
*/ |
*/ |
196 |
if ((ip->ip_off & htons(0x3fff)) || mlen < 40) |
if ((ip->ip_off & htons (0x3fff)) || mlen < 40) |
197 |
return (TYPE_IP); |
return (TYPE_IP); |
198 |
|
|
199 |
th = (struct tcphdr *)&((int *)ip)[hlen]; |
th = (struct tcphdr *) &((int *) ip)[hlen]; |
200 |
if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) |
if ((th->th_flags & (TH_SYN | TH_FIN | TH_RST | TH_ACK)) != TH_ACK) |
201 |
return (TYPE_IP); |
return (TYPE_IP); |
202 |
/* |
/* |
203 |
* Packet is compressible -- we're going to send either a |
* Packet is compressible -- we're going to send either a |
204 |
* COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need |
* COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need |
205 |
* to locate (or create) the connection state. Special case the |
* to locate (or create) the connection state. Special case the |
206 |
* most recently used connection since it's most likely to be used |
* most recently used connection since it's most likely to be used |
207 |
* again & we don't have to do any reordering if it's used. |
* again & we don't have to do any reordering if it's used. |
208 |
*/ |
*/ |
209 |
INCR(vjs_packets); |
INCR (vjs_packets); |
210 |
if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || |
if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || |
211 |
ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || |
ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || |
212 |
*(int *)th != ((int *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) { |
*(int *) th != ((int *) &cs->cs_ip)[getip_hl (cs->cs_ip)]) |
213 |
/* |
{ |
214 |
* Wasn't the first -- search for it. |
/* |
215 |
* |
* Wasn't the first -- search for it. |
216 |
* States are kept in a circularly linked list with |
* |
217 |
* last_cs pointing to the end of the list. The |
* States are kept in a circularly linked list with |
218 |
* list is kept in lru order by moving a state to the |
* last_cs pointing to the end of the list. The |
219 |
* head of the list whenever it is referenced. Since |
* list is kept in lru order by moving a state to the |
220 |
* the list is short and, empirically, the connection |
* head of the list whenever it is referenced. Since |
221 |
* we want is almost always near the front, we locate |
* the list is short and, empirically, the connection |
222 |
* states via linear search. If we don't find a state |
* we want is almost always near the front, we locate |
223 |
* for the datagram, the oldest state is (re-)used. |
* states via linear search. If we don't find a state |
224 |
*/ |
* for the datagram, the oldest state is (re-)used. |
225 |
register struct cstate *lcs; |
*/ |
226 |
register struct cstate *lastcs = comp->last_cs; |
register struct cstate *lcs; |
227 |
|
register struct cstate *lastcs = comp->last_cs; |
228 |
do { |
|
229 |
lcs = cs; cs = cs->cs_next; |
do |
230 |
INCR(vjs_searches); |
{ |
231 |
if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr |
lcs = cs; |
232 |
&& ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr |
cs = cs->cs_next; |
233 |
&& *(int *)th == ((int *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) |
INCR (vjs_searches); |
234 |
goto found; |
if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr |
235 |
} while (cs != lastcs); |
&& ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr |
236 |
|
&& *(int *) th == ((int *) &cs->cs_ip)[getip_hl (cs->cs_ip)]) |
237 |
/* |
goto found; |
238 |
* Didn't find it -- re-use oldest cstate. Send an |
} |
239 |
* uncompressed packet that tells the other side what |
while (cs != lastcs); |
240 |
* connection number we're using for this conversation. |
|
241 |
* Note that since the state list is circular, the oldest |
/* |
242 |
* state points to the newest and we only need to set |
* Didn't find it -- re-use oldest cstate. Send an |
243 |
* last_cs to update the lru linkage. |
* uncompressed packet that tells the other side what |
244 |
*/ |
* connection number we're using for this conversation. |
245 |
INCR(vjs_misses); |
* Note that since the state list is circular, the oldest |
246 |
comp->last_cs = lcs; |
* state points to the newest and we only need to set |
247 |
hlen += getth_off(*th); |
* last_cs to update the lru linkage. |
248 |
hlen <<= 2; |
*/ |
249 |
if (hlen > mlen) |
INCR (vjs_misses); |
250 |
return (TYPE_IP); |
comp->last_cs = lcs; |
251 |
goto uncompressed; |
hlen += getth_off (*th); |
252 |
|
hlen <<= 2; |
253 |
|
if (hlen > mlen) |
254 |
|
return (TYPE_IP); |
255 |
|
goto uncompressed; |
256 |
|
|
257 |
found: |
found: |
258 |
/* |
/* |
259 |
* Found it -- move to the front on the connection list. |
* Found it -- move to the front on the connection list. |
260 |
*/ |
*/ |
261 |
if (cs == lastcs) |
if (cs == lastcs) |
262 |
comp->last_cs = lcs; |
comp->last_cs = lcs; |
263 |
else { |
else |
264 |
lcs->cs_next = cs->cs_next; |
{ |
265 |
cs->cs_next = lastcs->cs_next; |
lcs->cs_next = cs->cs_next; |
266 |
lastcs->cs_next = cs; |
cs->cs_next = lastcs->cs_next; |
267 |
} |
lastcs->cs_next = cs; |
268 |
} |
} |
269 |
|
} |
270 |
/* |
|
271 |
* Make sure that only what we expect to change changed. The first |
/* |
272 |
* line of the `if' checks the IP protocol version, header length & |
* Make sure that only what we expect to change changed. The first |
273 |
* type of service. The 2nd line checks the "Don't fragment" bit. |
* line of the `if' checks the IP protocol version, header length & |
274 |
* The 3rd line checks the time-to-live and protocol (the protocol |
* type of service. The 2nd line checks the "Don't fragment" bit. |
275 |
* check is unnecessary but costless). The 4th line checks the TCP |
* The 3rd line checks the time-to-live and protocol (the protocol |
276 |
* header length. The 5th line checks IP options, if any. The 6th |
* check is unnecessary but costless). The 4th line checks the TCP |
277 |
* line checks TCP options, if any. If any of these things are |
* header length. The 5th line checks IP options, if any. The 6th |
278 |
* different between the previous & current datagram, we send the |
* line checks TCP options, if any. If any of these things are |
279 |
* current datagram `uncompressed'. |
* different between the previous & current datagram, we send the |
280 |
*/ |
* current datagram `uncompressed'. |
281 |
oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen]; |
*/ |
282 |
deltaS = hlen; |
oth = (struct tcphdr *) &((int *) &cs->cs_ip)[hlen]; |
283 |
hlen += getth_off(*th); |
deltaS = hlen; |
284 |
hlen <<= 2; |
hlen += getth_off (*th); |
285 |
if (hlen > mlen) |
hlen <<= 2; |
286 |
return (TYPE_IP); |
if (hlen > mlen) |
287 |
|
return (TYPE_IP); |
288 |
if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] || |
|
289 |
((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] || |
if (((u_short *) ip)[0] != ((u_short *) & cs->cs_ip)[0] || |
290 |
((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] || |
((u_short *) ip)[3] != ((u_short *) & cs->cs_ip)[3] || |
291 |
getth_off(*th) != getth_off(*oth) || |
((u_short *) ip)[4] != ((u_short *) & cs->cs_ip)[4] || |
292 |
(deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || |
getth_off (*th) != getth_off (*oth) || |
293 |
(getth_off(*th) > 5 && BCMP(th + 1, oth + 1, (getth_off(*th) - 5) << 2))) |
(deltaS > 5 && BCMP (ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || |
294 |
goto uncompressed; |
(getth_off (*th) > 5 |
295 |
|
&& BCMP (th + 1, oth + 1, (getth_off (*th) - 5) << 2))) |
296 |
/* |
goto uncompressed; |
297 |
* Figure out which of the changing fields changed. The |
|
298 |
* receiver expects changes in the order: urgent, window, |
/* |
299 |
* ack, seq (the order minimizes the number of temporaries |
* Figure out which of the changing fields changed. The |
300 |
* needed in this section of code). |
* receiver expects changes in the order: urgent, window, |
301 |
*/ |
* ack, seq (the order minimizes the number of temporaries |
302 |
if (th->th_flags & TH_URG) { |
* needed in this section of code). |
303 |
deltaS = ntohs(th->th_urp); |
*/ |
304 |
ENCODEZ(deltaS); |
if (th->th_flags & TH_URG) |
305 |
changes |= NEW_U; |
{ |
306 |
} else if (th->th_urp != oth->th_urp) |
deltaS = ntohs (th->th_urp); |
307 |
/* argh! URG not set but urp changed -- a sensible |
ENCODEZ (deltaS); |
308 |
* implementation should never do this but RFC793 |
changes |= NEW_U; |
309 |
* doesn't prohibit the change so we have to deal |
} |
310 |
* with it. */ |
else if (th->th_urp != oth->th_urp) |
311 |
goto uncompressed; |
/* argh! URG not set but urp changed -- a sensible |
312 |
|
* implementation should never do this but RFC793 |
313 |
if (deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) { |
* doesn't prohibit the change so we have to deal |
314 |
ENCODE(deltaS); |
* with it. */ |
315 |
changes |= NEW_W; |
goto uncompressed; |
316 |
} |
|
317 |
|
if ((deltaS = (u_short) (ntohs (th->th_win) - ntohs (oth->th_win)))) |
318 |
if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) { |
{ |
319 |
if (deltaA > 0xffff) |
ENCODE (deltaS); |
320 |
goto uncompressed; |
changes |= NEW_W; |
321 |
ENCODE(deltaA); |
} |
322 |
changes |= NEW_A; |
|
323 |
} |
if ((deltaA = ntohl (th->th_ack) - ntohl (oth->th_ack))) |
324 |
|
{ |
325 |
if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) { |
if (deltaA > 0xffff) |
326 |
if (deltaS > 0xffff) |
goto uncompressed; |
327 |
goto uncompressed; |
ENCODE (deltaA); |
328 |
ENCODE(deltaS); |
changes |= NEW_A; |
329 |
changes |= NEW_S; |
} |
330 |
|
|
331 |
|
if ((deltaS = ntohl (th->th_seq) - ntohl (oth->th_seq))) |
332 |
|
{ |
333 |
|
if (deltaS > 0xffff) |
334 |
|
goto uncompressed; |
335 |
|
ENCODE (deltaS); |
336 |
|
changes |= NEW_S; |
337 |
} |
} |
338 |
|
|
339 |
switch(changes) { |
switch (changes) |
340 |
|
{ |
341 |
|
|
342 |
case 0: |
case 0: |
343 |
/* |
/* |
344 |
* Nothing changed. If this packet contains data and the |
* Nothing changed. If this packet contains data and the |
345 |
* last one didn't, this is probably a data packet following |
* last one didn't, this is probably a data packet following |
346 |
* an ack (normal on an interactive connection) and we send |
* an ack (normal on an interactive connection) and we send |
347 |
* it compressed. Otherwise it's probably a retransmit, |
* it compressed. Otherwise it's probably a retransmit, |
348 |
* retransmitted ack or window probe. Send it uncompressed |
* retransmitted ack or window probe. Send it uncompressed |
349 |
* in case the other side missed the compressed version. |
* in case the other side missed the compressed version. |
350 |
*/ |
*/ |
351 |
if (ip->ip_len != cs->cs_ip.ip_len && |
if (ip->ip_len != cs->cs_ip.ip_len && ntohs (cs->cs_ip.ip_len) == hlen) |
352 |
ntohs(cs->cs_ip.ip_len) == hlen) |
break; |
|
break; |
|
353 |
|
|
354 |
/* (fall through) */ |
/* (fall through) */ |
355 |
|
|
356 |
case SPECIAL_I: |
case SPECIAL_I: |
357 |
case SPECIAL_D: |
case SPECIAL_D: |
358 |
/* |
/* |
359 |
* actual changes match one of our special case encodings -- |
* actual changes match one of our special case encodings -- |
360 |
* send packet uncompressed. |
* send packet uncompressed. |
361 |
*/ |
*/ |
362 |
goto uncompressed; |
goto uncompressed; |
363 |
|
|
364 |
case NEW_S|NEW_A: |
case NEW_S | NEW_A: |
365 |
if (deltaS == deltaA && deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { |
if (deltaS == deltaA && deltaS == ntohs (cs->cs_ip.ip_len) - hlen) |
366 |
/* special case for echoed terminal traffic */ |
{ |
367 |
changes = SPECIAL_I; |
/* special case for echoed terminal traffic */ |
368 |
cp = new_seq; |
changes = SPECIAL_I; |
369 |
} |
cp = new_seq; |
370 |
break; |
} |
371 |
|
break; |
372 |
|
|
373 |
case NEW_S: |
case NEW_S: |
374 |
if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { |
if (deltaS == ntohs (cs->cs_ip.ip_len) - hlen) |
375 |
/* special case for data xfer */ |
{ |
376 |
changes = SPECIAL_D; |
/* special case for data xfer */ |
377 |
cp = new_seq; |
changes = SPECIAL_D; |
378 |
} |
cp = new_seq; |
379 |
break; |
} |
380 |
} |
break; |
381 |
|
} |
382 |
deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); |
|
383 |
if (deltaS != 1) { |
deltaS = ntohs (ip->ip_id) - ntohs (cs->cs_ip.ip_id); |
384 |
ENCODEZ(deltaS); |
if (deltaS != 1) |
385 |
changes |= NEW_I; |
{ |
386 |
} |
ENCODEZ (deltaS); |
387 |
if (th->th_flags & TH_PUSH) |
changes |= NEW_I; |
388 |
changes |= TCP_PUSH_BIT; |
} |
389 |
/* |
if (th->th_flags & TH_PUSH) |
390 |
* Grab the cksum before we overwrite it below. Then update our |
changes |= TCP_PUSH_BIT; |
391 |
* state with this packet's header. |
/* |
392 |
*/ |
* Grab the cksum before we overwrite it below. Then update our |
393 |
deltaA = ntohs(th->th_sum); |
* state with this packet's header. |
394 |
BCOPY(ip, &cs->cs_ip, hlen); |
*/ |
395 |
|
deltaA = ntohs (th->th_sum); |
396 |
/* |
BCOPY (ip, &cs->cs_ip, hlen); |
397 |
* We want to use the original packet as our compressed packet. |
|
398 |
* (cp - new_seq) is the number of bytes we need for compressed |
/* |
399 |
* sequence numbers. In addition we need one byte for the change |
* We want to use the original packet as our compressed packet. |
400 |
* mask, one for the connection id and two for the tcp checksum. |
* (cp - new_seq) is the number of bytes we need for compressed |
401 |
* So, (cp - new_seq) + 4 bytes of header are needed. hlen is how |
* sequence numbers. In addition we need one byte for the change |
402 |
* many bytes of the original packet to toss so subtract the two to |
* mask, one for the connection id and two for the tcp checksum. |
403 |
* get the new packet size. |
* So, (cp - new_seq) + 4 bytes of header are needed. hlen is how |
404 |
*/ |
* many bytes of the original packet to toss so subtract the two to |
405 |
deltaS = cp - new_seq; |
* get the new packet size. |
406 |
cp = (u_char *)ip; |
*/ |
407 |
if (compress_cid == 0 || comp->last_xmit != cs->cs_id) { |
deltaS = cp - new_seq; |
408 |
comp->last_xmit = cs->cs_id; |
cp = (u_char *) ip; |
409 |
hlen -= deltaS + 4; |
if (compress_cid == 0 || comp->last_xmit != cs->cs_id) |
410 |
*vjhdrp = (cp += hlen); |
{ |
411 |
*cp++ = changes | NEW_C; |
comp->last_xmit = cs->cs_id; |
412 |
*cp++ = cs->cs_id; |
hlen -= deltaS + 4; |
413 |
} else { |
*vjhdrp = (cp += hlen); |
414 |
hlen -= deltaS + 3; |
*cp++ = changes | NEW_C; |
415 |
*vjhdrp = (cp += hlen); |
*cp++ = cs->cs_id; |
416 |
*cp++ = changes; |
} |
417 |
} |
else |
418 |
*cp++ = deltaA >> 8; |
{ |
419 |
*cp++ = deltaA; |
hlen -= deltaS + 3; |
420 |
BCOPY(new_seq, cp, deltaS); |
*vjhdrp = (cp += hlen); |
421 |
INCR(vjs_compressed); |
*cp++ = changes; |
422 |
return (TYPE_COMPRESSED_TCP); |
} |
423 |
|
*cp++ = deltaA >> 8; |
424 |
/* |
*cp++ = deltaA; |
425 |
* Update connection state cs & send uncompressed packet (that is, |
BCOPY (new_seq, cp, deltaS); |
426 |
* a regular ip/tcp packet but with the 'conversation id' we hope |
INCR (vjs_compressed); |
427 |
* to use on future compressed packets in the protocol field). |
return (TYPE_COMPRESSED_TCP); |
428 |
*/ |
|
429 |
uncompressed: |
/* |
430 |
BCOPY(ip, &cs->cs_ip, hlen); |
* Update connection state cs & send uncompressed packet (that is, |
431 |
ip->ip_p = cs->cs_id; |
* a regular ip/tcp packet but with the 'conversation id' we hope |
432 |
comp->last_xmit = cs->cs_id; |
* to use on future compressed packets in the protocol field). |
433 |
return (TYPE_UNCOMPRESSED_TCP); |
*/ |
434 |
|
uncompressed: |
435 |
|
BCOPY (ip, &cs->cs_ip, hlen); |
436 |
|
ip->ip_p = cs->cs_id; |
437 |
|
comp->last_xmit = cs->cs_id; |
438 |
|
return (TYPE_UNCOMPRESSED_TCP); |
439 |
} |
} |
440 |
|
|
441 |
/* |
/* |
442 |
* Called when we may have missed a packet. |
* Called when we may have missed a packet. |
443 |
*/ |
*/ |
444 |
void |
void |
445 |
vj_uncompress_err(comp) |
vj_uncompress_err (comp) |
446 |
struct vjcompress *comp; |
struct vjcompress *comp; |
447 |
{ |
{ |
448 |
comp->flags |= VJF_TOSS; |
comp->flags |= VJF_TOSS; |
449 |
INCR(vjs_errorin); |
INCR (vjs_errorin); |
450 |
} |
} |
451 |
|
|
452 |
/* |
/* |
453 |
* "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP. |
* "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP. |
454 |
*/ |
*/ |
455 |
int |
int |
456 |
vj_uncompress_uncomp(buf, buflen, comp) |
vj_uncompress_uncomp (buf, buflen, comp) |
457 |
u_char *buf; |
u_char *buf; |
458 |
int buflen; |
int buflen; |
459 |
struct vjcompress *comp; |
struct vjcompress *comp; |
460 |
{ |
{ |
461 |
register u_int hlen; |
register u_int hlen; |
462 |
register struct cstate *cs; |
register struct cstate *cs; |
463 |
register struct ip *ip; |
register struct ip *ip; |
464 |
|
|
465 |
ip = (struct ip *) buf; |
ip = (struct ip *) buf; |
466 |
hlen = getip_hl(*ip) << 2; |
hlen = getip_hl (*ip) << 2; |
467 |
if (ip->ip_p >= MAX_STATES |
if (ip->ip_p >= MAX_STATES |
468 |
|| hlen + sizeof(struct tcphdr) > buflen |
|| hlen + sizeof (struct tcphdr) > buflen |
469 |
|| (hlen += getth_off(*((struct tcphdr *)&((char *)ip)[hlen])) << 2) |
|| (hlen += getth_off (*((struct tcphdr *) &((char *) ip)[hlen])) << 2) |
470 |
> buflen |
> buflen || hlen > MAX_HDR) |
471 |
|| hlen > MAX_HDR) { |
{ |
472 |
comp->flags |= VJF_TOSS; |
comp->flags |= VJF_TOSS; |
473 |
INCR(vjs_errorin); |
INCR (vjs_errorin); |
474 |
return (0); |
return (0); |
475 |
} |
} |
476 |
cs = &comp->rstate[comp->last_recv = ip->ip_p]; |
cs = &comp->rstate[comp->last_recv = ip->ip_p]; |
477 |
comp->flags &=~ VJF_TOSS; |
comp->flags &= ~VJF_TOSS; |
478 |
ip->ip_p = IPPROTO_TCP; |
ip->ip_p = IPPROTO_TCP; |
479 |
BCOPY(ip, &cs->cs_ip, hlen); |
BCOPY (ip, &cs->cs_ip, hlen); |
480 |
cs->cs_hlen = hlen; |
cs->cs_hlen = hlen; |
481 |
INCR(vjs_uncompressedin); |
INCR (vjs_uncompressedin); |
482 |
return (1); |
return (1); |
483 |
} |
} |
484 |
|
|
485 |
/* |
/* |
491 |
* in *hdrp and its length in *hlenp. |
* in *hdrp and its length in *hlenp. |
492 |
*/ |
*/ |
493 |
int |
int |
494 |
vj_uncompress_tcp(buf, buflen, total_len, comp, hdrp, hlenp) |
vj_uncompress_tcp (buf, buflen, total_len, comp, hdrp, hlenp) |
495 |
u_char *buf; |
u_char *buf; |
496 |
int buflen, total_len; |
int buflen, total_len; |
497 |
struct vjcompress *comp; |
struct vjcompress *comp; |
498 |
u_char **hdrp; |
u_char **hdrp; |
499 |
u_int *hlenp; |
u_int *hlenp; |
500 |
{ |
{ |
501 |
register u_char *cp; |
register u_char *cp; |
502 |
register u_int hlen, changes; |
register u_int hlen, changes; |
503 |
register struct tcphdr *th; |
register struct tcphdr *th; |
504 |
register struct cstate *cs; |
register struct cstate *cs; |
505 |
register u_short *bp; |
register u_short *bp; |
506 |
register u_int vjlen; |
register u_int vjlen; |
507 |
register u_int32_t tmp; |
register u_int32_t tmp; |
508 |
|
|
509 |
INCR(vjs_compressedin); |
INCR (vjs_compressedin); |
510 |
cp = buf; |
cp = buf; |
511 |
changes = *cp++; |
changes = *cp++; |
512 |
if (changes & NEW_C) { |
if (changes & NEW_C) |
513 |
/* Make sure the state index is in range, then grab the state. |
{ |
514 |
* If we have a good state index, clear the 'discard' flag. */ |
/* Make sure the state index is in range, then grab the state. |
515 |
if (*cp >= MAX_STATES) |
* If we have a good state index, clear the 'discard' flag. */ |
516 |
goto bad; |
if (*cp >= MAX_STATES) |
517 |
|
goto bad; |
518 |
comp->flags &=~ VJF_TOSS; |
|
519 |
comp->last_recv = *cp++; |
comp->flags &= ~VJF_TOSS; |
520 |
} else { |
comp->last_recv = *cp++; |
521 |
/* this packet has an implicit state index. If we've |
} |
522 |
* had a line error since the last time we got an |
else |
523 |
* explicit state index, we have to toss the packet. */ |
{ |
524 |
if (comp->flags & VJF_TOSS) { |
/* this packet has an implicit state index. If we've |
525 |
INCR(vjs_tossed); |
* had a line error since the last time we got an |
526 |
return (-1); |
* explicit state index, we have to toss the packet. */ |
527 |
} |
if (comp->flags & VJF_TOSS) |
528 |
} |
{ |
529 |
cs = &comp->rstate[comp->last_recv]; |
INCR (vjs_tossed); |
530 |
hlen = getip_hl(cs->cs_ip) << 2; |
return (-1); |
531 |
th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; |
} |
532 |
th->th_sum = htons((*cp << 8) | cp[1]); |
} |
533 |
cp += 2; |
cs = &comp->rstate[comp->last_recv]; |
534 |
if (changes & TCP_PUSH_BIT) |
hlen = getip_hl (cs->cs_ip) << 2; |
535 |
th->th_flags |= TH_PUSH; |
th = (struct tcphdr *) &((u_char *) & cs->cs_ip)[hlen]; |
536 |
else |
th->th_sum = htons ((*cp << 8) | cp[1]); |
537 |
th->th_flags &=~ TH_PUSH; |
cp += 2; |
538 |
|
if (changes & TCP_PUSH_BIT) |
539 |
|
th->th_flags |= TH_PUSH; |
540 |
|
else |
541 |
|
th->th_flags &= ~TH_PUSH; |
542 |
|
|
543 |
switch (changes & SPECIALS_MASK) { |
switch (changes & SPECIALS_MASK) |
544 |
|
{ |
545 |
case SPECIAL_I: |
case SPECIAL_I: |
546 |
{ |
{ |
547 |
register u_int32_t i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; |
register u_int32_t i = ntohs (cs->cs_ip.ip_len) - cs->cs_hlen; |
548 |
/* some compilers can't nest inline assembler.. */ |
/* some compilers can't nest inline assembler.. */ |
549 |
tmp = ntohl(th->th_ack) + i; |
tmp = ntohl (th->th_ack) + i; |
550 |
th->th_ack = htonl(tmp); |
th->th_ack = htonl (tmp); |
551 |
tmp = ntohl(th->th_seq) + i; |
tmp = ntohl (th->th_seq) + i; |
552 |
th->th_seq = htonl(tmp); |
th->th_seq = htonl (tmp); |
553 |
} |
} |
554 |
break; |
break; |
555 |
|
|
556 |
case SPECIAL_D: |
case SPECIAL_D: |
557 |
/* some compilers can't nest inline assembler.. */ |
/* some compilers can't nest inline assembler.. */ |
558 |
tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; |
tmp = ntohl (th->th_seq) + ntohs (cs->cs_ip.ip_len) - cs->cs_hlen; |
559 |
th->th_seq = htonl(tmp); |
th->th_seq = htonl (tmp); |
560 |
break; |
break; |
561 |
|
|
562 |
default: |
default: |
563 |
if (changes & NEW_U) { |
if (changes & NEW_U) |
564 |
th->th_flags |= TH_URG; |
{ |
565 |
DECODEU(th->th_urp); |
th->th_flags |= TH_URG; |
566 |
} else |
DECODEU (th->th_urp); |
567 |
th->th_flags &=~ TH_URG; |
} |
568 |
if (changes & NEW_W) |
else |
569 |
DECODES(th->th_win); |
th->th_flags &= ~TH_URG; |
570 |
if (changes & NEW_A) |
if (changes & NEW_W) |
571 |
DECODEL(th->th_ack); |
DECODES (th->th_win); |
572 |
if (changes & NEW_S) |
if (changes & NEW_A) |
573 |
DECODEL(th->th_seq); |
DECODEL (th->th_ack); |
574 |
break; |
if (changes & NEW_S) |
575 |
} |
DECODEL (th->th_seq); |
576 |
if (changes & NEW_I) { |
break; |
577 |
DECODES(cs->cs_ip.ip_id); |
} |
578 |
} else { |
if (changes & NEW_I) |
579 |
cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1; |
{ |
580 |
cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id); |
DECODES (cs->cs_ip.ip_id); |
581 |
} |
} |
582 |
|
else |
583 |
/* |
{ |
584 |
* At this point, cp points to the first byte of data in the |
cs->cs_ip.ip_id = ntohs (cs->cs_ip.ip_id) + 1; |
585 |
* packet. Fill in the IP total length and update the IP |
cs->cs_ip.ip_id = htons (cs->cs_ip.ip_id); |
586 |
* header checksum. |
} |
587 |
*/ |
|
588 |
vjlen = cp - buf; |
/* |
589 |
buflen -= vjlen; |
* At this point, cp points to the first byte of data in the |
590 |
if (buflen < 0) |
* packet. Fill in the IP total length and update the IP |
591 |
/* we must have dropped some characters (crc should detect |
* header checksum. |
592 |
* this but the old slip framing won't) */ |
*/ |
593 |
goto bad; |
vjlen = cp - buf; |
594 |
|
buflen -= vjlen; |
595 |
total_len += cs->cs_hlen - vjlen; |
if (buflen < 0) |
596 |
cs->cs_ip.ip_len = htons(total_len); |
/* we must have dropped some characters (crc should detect |
597 |
|
* this but the old slip framing won't) */ |
598 |
/* recompute the ip header checksum */ |
goto bad; |
599 |
bp = (u_short *) &cs->cs_ip; |
|
600 |
cs->cs_ip.ip_sum = 0; |
total_len += cs->cs_hlen - vjlen; |
601 |
for (changes = 0; hlen > 0; hlen -= 2) |
cs->cs_ip.ip_len = htons (total_len); |
602 |
changes += *bp++; |
|
603 |
changes = (changes & 0xffff) + (changes >> 16); |
/* recompute the ip header checksum */ |
604 |
changes = (changes & 0xffff) + (changes >> 16); |
bp = (u_short *) & cs->cs_ip; |
605 |
cs->cs_ip.ip_sum = ~ changes; |
cs->cs_ip.ip_sum = 0; |
606 |
|
for (changes = 0; hlen > 0; hlen -= 2) |
607 |
*hdrp = (u_char *) &cs->cs_ip; |
changes += *bp++; |
608 |
*hlenp = cs->cs_hlen; |
changes = (changes & 0xffff) + (changes >> 16); |
609 |
return vjlen; |
changes = (changes & 0xffff) + (changes >> 16); |
610 |
|
cs->cs_ip.ip_sum = ~changes; |
611 |
bad: |
|
612 |
comp->flags |= VJF_TOSS; |
*hdrp = (u_char *) & cs->cs_ip; |
613 |
INCR(vjs_errorin); |
*hlenp = cs->cs_hlen; |
614 |
return (-1); |
return vjlen; |
615 |
|
|
616 |
|
bad: |
617 |
|
comp->flags |= VJF_TOSS; |
618 |
|
INCR (vjs_errorin); |
619 |
|
return (-1); |
620 |
} |
} |