slcompress.c revision 26516
16059Samurai/* 26059Samurai * Routines to compress and uncompess tcp packets (for transmission 36059Samurai * over low speed serial lines. 46059Samurai * 56059Samurai * Copyright (c) 1989 Regents of the University of California. 66059Samurai * All rights reserved. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the University of California, Berkeley. The name of the 146059Samurai * University may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 196059Samurai * 2026516Sbrian * $Id: slcompress.c,v 1.8 1997/02/22 16:10:54 peter Exp $ 218857Srgrimes * 226059Samurai * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: 236059Samurai * - Initial distribution. 246059Samurai */ 256059Samurai#ifndef lint 2626516Sbrianstatic char const rcsid[] = "$Id: slcompress.c,v 1.8 1997/02/22 16:10:54 peter Exp $"; 276059Samurai#endif 286059Samurai 296059Samurai#include "defs.h" 306059Samurai#include <netinet/in_systm.h> 316059Samurai#include <netinet/in.h> 326059Samurai#include <netinet/tcp.h> 336059Samurai#include <netinet/ip.h> 346059Samurai#include "slcompress.h" 3526516Sbrian#include "loadalias.h" 3626516Sbrian#include "vars.h" 376059Samurai 386059Samuraistruct slstat slstat; 396059Samurai 406059Samurai#define INCR(counter) slstat.counter++; 416059Samurai 426059Samurai#define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n)) 436059Samurai#define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n)) 446059Samurai#ifndef KERNEL 456059Samurai#define ovbcopy bcopy 466059Samurai#endif 476059Samurai 486059Samuraivoid 496059Samuraisl_compress_init(comp) 506059Samurai struct slcompress *comp; 516059Samurai{ 526059Samurai register u_int i; 536059Samurai register struct cstate *tstate = comp->tstate; 546059Samurai 556059Samurai bzero((char *)comp, sizeof(*comp)); 566059Samurai for (i = MAX_STATES - 1; i > 0; --i) { 576059Samurai tstate[i].cs_id = i; 586059Samurai tstate[i].cs_next = &tstate[i - 1]; 596059Samurai } 606059Samurai tstate[0].cs_next = &tstate[MAX_STATES - 1]; 616059Samurai tstate[0].cs_id = 0; 626059Samurai comp->last_cs = &tstate[0]; 636059Samurai comp->last_recv = 255; 646059Samurai comp->last_xmit = 255; 656059Samurai comp->flags = SLF_TOSS; 666059Samurai} 676059Samurai 686059Samurai 696059Samurai/* ENCODE encodes a number that is known to be non-zero. ENCODEZ 706059Samurai * checks for zero (since zero has to be encoded in the long, 3 byte 716059Samurai * form). 726059Samurai */ 736059Samurai#define ENCODE(n) { \ 746059Samurai if ((u_short)(n) >= 256) { \ 756059Samurai *cp++ = 0; \ 766059Samurai cp[1] = (n); \ 776059Samurai cp[0] = (n) >> 8; \ 786059Samurai cp += 2; \ 796059Samurai } else { \ 806059Samurai *cp++ = (n); \ 816059Samurai } \ 826059Samurai} 836059Samurai#define ENCODEZ(n) { \ 846059Samurai if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ 856059Samurai *cp++ = 0; \ 866059Samurai cp[1] = (n); \ 876059Samurai cp[0] = (n) >> 8; \ 886059Samurai cp += 2; \ 896059Samurai } else { \ 906059Samurai *cp++ = (n); \ 916059Samurai } \ 926059Samurai} 936059Samurai 946059Samurai#define DECODEL(f) { \ 956059Samurai if (*cp == 0) {\ 966059Samurai (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \ 976059Samurai cp += 3; \ 986059Samurai } else { \ 996059Samurai (f) = htonl(ntohl(f) + (u_long)*cp++); \ 1006059Samurai } \ 1016059Samurai} 1026059Samurai 1036059Samurai#define DECODES(f) { \ 1046059Samurai if (*cp == 0) {\ 1056059Samurai (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \ 1066059Samurai cp += 3; \ 1076059Samurai } else { \ 1086059Samurai (f) = htons(ntohs(f) + (u_long)*cp++); \ 1096059Samurai } \ 1106059Samurai} 1116059Samurai 1126059Samurai#define DECODEU(f) { \ 1136059Samurai if (*cp == 0) {\ 1146059Samurai (f) = htons((cp[1] << 8) | cp[2]); \ 1156059Samurai cp += 3; \ 1166059Samurai } else { \ 1176059Samurai (f) = htons((u_long)*cp++); \ 1186059Samurai } \ 1196059Samurai} 1206059Samurai 1216059Samurai 1226059Samuraiu_char 1236059Samuraisl_compress_tcp(m, ip, comp, compress_cid) 1246059Samurai struct mbuf *m; 1256059Samurai register struct ip *ip; 1266059Samurai struct slcompress *comp; 1276059Samurai int compress_cid; 1286059Samurai{ 1296059Samurai register struct cstate *cs = comp->last_cs->cs_next; 1306059Samurai register u_int hlen = ip->ip_hl; 1316059Samurai register struct tcphdr *oth; 1326059Samurai register struct tcphdr *th; 1336059Samurai register u_int deltaS, deltaA; 1346059Samurai register u_int changes = 0; 1356059Samurai u_char new_seq[16]; 1366059Samurai register u_char *cp = new_seq; 1376059Samurai 1386059Samurai /* 1396059Samurai * Bail if this is an IP fragment or if the TCP packet isn't 1406059Samurai * `compressible' (i.e., ACK isn't set or some other control bit is 1416059Samurai * set). (We assume that the caller has already made sure the 1426059Samurai * packet is IP proto TCP). 1436059Samurai */ 1446059Samurai if ((ip->ip_off & htons(0x3fff)) || m->cnt < 40) { 14526516Sbrian LogPrintf(LogDEBUG, "??? 1 ip_off = %x, cnt = %d\n", 14626516Sbrian ip->ip_off, m->cnt); 14726516Sbrian LogDumpBp(LogDEBUG, "", m); 1486059Samurai return (TYPE_IP); 1496059Samurai } 1506059Samurai 1516059Samurai th = (struct tcphdr *)&((int *)ip)[hlen]; 1526059Samurai if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) { 15326516Sbrian LogPrintf(LogDEBUG, "??? 2 th_flags = %x\n", th->th_flags); 15426516Sbrian LogDumpBp(LogDEBUG, "", m); 1556059Samurai return (TYPE_IP); 1566059Samurai } 1576059Samurai 1586059Samurai /* 1596059Samurai * Packet is compressible -- we're going to send either a 1606059Samurai * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need 1616059Samurai * to locate (or create) the connection state. Special case the 1626059Samurai * most recently used connection since it's most likely to be used 1636059Samurai * again & we don't have to do any reordering if it's used. 1646059Samurai */ 1656059Samurai INCR(sls_packets) 1666059Samurai if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || 1676059Samurai ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || 1686059Samurai *(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) { 1696059Samurai /* 1706059Samurai * Wasn't the first -- search for it. 1716059Samurai * 1726059Samurai * States are kept in a circularly linked list with 1736059Samurai * last_cs pointing to the end of the list. The 1746059Samurai * list is kept in lru order by moving a state to the 1756059Samurai * head of the list whenever it is referenced. Since 1766059Samurai * the list is short and, empirically, the connection 1776059Samurai * we want is almost always near the front, we locate 1786059Samurai * states via linear search. If we don't find a state 1796059Samurai * for the datagram, the oldest state is (re-)used. 1806059Samurai */ 1816059Samurai register struct cstate *lcs; 1826059Samurai register struct cstate *lastcs = comp->last_cs; 1836059Samurai 1846059Samurai do { 1856059Samurai lcs = cs; cs = cs->cs_next; 1866059Samurai INCR(sls_searches) 1876059Samurai if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr 1886059Samurai && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr 1896059Samurai && *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) 1906059Samurai goto found; 1916059Samurai } while (cs != lastcs); 1926059Samurai 1936059Samurai /* 1946059Samurai * Didn't find it -- re-use oldest cstate. Send an 1956059Samurai * uncompressed packet that tells the other side what 1966059Samurai * connection number we're using for this conversation. 1976059Samurai * Note that since the state list is circular, the oldest 1986059Samurai * state points to the newest and we only need to set 1996059Samurai * last_cs to update the lru linkage. 2006059Samurai */ 2016059Samurai INCR(sls_misses) 2026059Samurai comp->last_cs = lcs; 2036059Samurai#define THOFFSET(th) (th->th_off) 2046059Samurai hlen += th->th_off; 2056059Samurai hlen <<= 2; 2066059Samurai if (hlen > m->cnt) 2076059Samurai return(TYPE_IP); 2086059Samurai goto uncompressed; 2096059Samurai 2106059Samurai found: 2116059Samurai /* 2126059Samurai * Found it -- move to the front on the connection list. 2136059Samurai */ 2146059Samurai if (cs == lastcs) 2156059Samurai comp->last_cs = lcs; 2166059Samurai else { 2176059Samurai lcs->cs_next = cs->cs_next; 2186059Samurai cs->cs_next = lastcs->cs_next; 2196059Samurai lastcs->cs_next = cs; 2206059Samurai } 2216059Samurai } 2226059Samurai 2236059Samurai /* 2246059Samurai * Make sure that only what we expect to change changed. The first 2256059Samurai * line of the `if' checks the IP protocol version, header length & 2266059Samurai * type of service. The 2nd line checks the "Don't fragment" bit. 2276059Samurai * The 3rd line checks the time-to-live and protocol (the protocol 2286059Samurai * check is unnecessary but costless). The 4th line checks the TCP 2296059Samurai * header length. The 5th line checks IP options, if any. The 6th 2306059Samurai * line checks TCP options, if any. If any of these things are 2316059Samurai * different between the previous & current datagram, we send the 2326059Samurai * current datagram `uncompressed'. 2336059Samurai */ 2346059Samurai oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen]; 2356059Samurai deltaS = hlen; 2366059Samurai hlen += th->th_off; 2376059Samurai hlen <<= 2; 2386059Samurai if (hlen > m->cnt) 2396059Samurai return(TYPE_IP); 2406059Samurai 2416059Samurai if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] || 2426059Samurai ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] || 2436059Samurai ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] || 2446059Samurai THOFFSET(th) != THOFFSET(oth) || 2456059Samurai (deltaS > 5 && 2466059Samurai BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || 2476059Samurai (THOFFSET(th) > 5 && 2486059Samurai BCMP(th + 1, oth + 1, (THOFFSET(th) - 5) << 2))) { 2496059Samurai goto uncompressed; 2506059Samurai } 2516059Samurai 2526059Samurai /* 2536059Samurai * Figure out which of the changing fields changed. The 2546059Samurai * receiver expects changes in the order: urgent, window, 2556059Samurai * ack, seq (the order minimizes the number of temporaries 2566059Samurai * needed in this section of code). 2576059Samurai */ 2586059Samurai if (th->th_flags & TH_URG) { 2596059Samurai deltaS = ntohs(th->th_urp); 2606059Samurai ENCODEZ(deltaS); 2616059Samurai changes |= NEW_U; 2626059Samurai } else if (th->th_urp != oth->th_urp) { 2636059Samurai /* argh! URG not set but urp changed -- a sensible 2646059Samurai * implementation should never do this but RFC793 2656059Samurai * doesn't prohibit the change so we have to deal 2666059Samurai * with it. */ 2676059Samurai goto uncompressed; 2686059Samurai } 2696059Samurai 2706059Samurai deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win)); 2716059Samurai if (deltaS) { 2726059Samurai ENCODE(deltaS); 2736059Samurai changes |= NEW_W; 2746059Samurai } 2756059Samurai 2766059Samurai deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack); 2776059Samurai if (deltaA) { 2786059Samurai if (deltaA > 0xffff) { 2796059Samurai goto uncompressed; 2806059Samurai } 2816059Samurai ENCODE(deltaA); 2826059Samurai changes |= NEW_A; 2836059Samurai } 2846059Samurai 2856059Samurai deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq); 2866059Samurai if (deltaS) { 2876059Samurai if (deltaS > 0xffff) { 2886059Samurai goto uncompressed; 2896059Samurai } 2906059Samurai ENCODE(deltaS); 2916059Samurai changes |= NEW_S; 2926059Samurai } 2936059Samurai 2946059Samurai switch(changes) { 2956059Samurai 2966059Samurai case 0: 2976059Samurai /* 2986059Samurai * Nothing changed. If this packet contains data and the 2996059Samurai * last one didn't, this is probably a data packet following 3006059Samurai * an ack (normal on an interactive connection) and we send 3016059Samurai * it compressed. Otherwise it's probably a retransmit, 3026059Samurai * retransmitted ack or window probe. Send it uncompressed 3036059Samurai * in case the other side missed the compressed version. 3046059Samurai */ 3056059Samurai if (ip->ip_len != cs->cs_ip.ip_len && 3066059Samurai ntohs(cs->cs_ip.ip_len) == hlen) 3076059Samurai break; 3086059Samurai 3096059Samurai /* (fall through) */ 3106059Samurai 3116059Samurai case SPECIAL_I: 3126059Samurai case SPECIAL_D: 3136059Samurai /* 3146059Samurai * actual changes match one of our special case encodings -- 3156059Samurai * send packet uncompressed. 3166059Samurai */ 3176059Samurai goto uncompressed; 3186059Samurai 3196059Samurai case NEW_S|NEW_A: 3206059Samurai if (deltaS == deltaA && 3216059Samurai deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { 3226059Samurai /* special case for echoed terminal traffic */ 3236059Samurai changes = SPECIAL_I; 3246059Samurai cp = new_seq; 3256059Samurai } 3266059Samurai break; 3276059Samurai 3286059Samurai case NEW_S: 3296059Samurai if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { 3306059Samurai /* special case for data xfer */ 3316059Samurai changes = SPECIAL_D; 3326059Samurai cp = new_seq; 3336059Samurai } 3346059Samurai break; 3356059Samurai } 3366059Samurai 3376059Samurai deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); 3386059Samurai if (deltaS != 1) { 3396059Samurai ENCODEZ(deltaS); 3406059Samurai changes |= NEW_I; 3416059Samurai } 3426059Samurai if (th->th_flags & TH_PUSH) 3436059Samurai changes |= TCP_PUSH_BIT; 3446059Samurai /* 3456059Samurai * Grab the cksum before we overwrite it below. Then update our 3466059Samurai * state with this packet's header. 3476059Samurai */ 3486059Samurai deltaA = ntohs(th->th_sum); 3496059Samurai BCOPY(ip, &cs->cs_ip, hlen); 3506059Samurai 3516059Samurai /* 3526059Samurai * We want to use the original packet as our compressed packet. 3536059Samurai * (cp - new_seq) is the number of bytes we need for compressed 3546059Samurai * sequence numbers. In addition we need one byte for the change 3556059Samurai * mask, one for the connection id and two for the tcp checksum. 3566059Samurai * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how 3576059Samurai * many bytes of the original packet to toss so subtract the two to 3586059Samurai * get the new packet size. 3596059Samurai */ 3606059Samurai deltaS = cp - new_seq; 3616059Samurai cp = (u_char *)ip; 3626059Samurai 3636059Samurai /* 3646059Samurai * Since fastq traffic can jump ahead of the background traffic, 3656059Samurai * we don't know what order packets will go on the line. In this 3666059Samurai * case, we always send a "new" connection id so the receiver state 3676059Samurai * stays synchronized. 3686059Samurai */ 3696059Samurai#ifdef SL_NOFASTQ 3706059Samurai if (comp->last_xmit == cs->cs_id) { 3716059Samurai hlen -= deltaS + 3; 3726059Samurai cp += hlen; 3736059Samurai *cp++ = changes; 3746059Samurai } else 3756059Samurai#endif 3766059Samurai { 3776059Samurai comp->last_xmit = cs->cs_id; 3786059Samurai hlen -= deltaS + 4; 3796059Samurai cp += hlen; 3806059Samurai *cp++ = changes | NEW_C; 3816059Samurai *cp++ = cs->cs_id; 3826059Samurai } 3836059Samurai m->cnt -= hlen; 3846059Samurai m->offset += hlen; 3856059Samurai *cp++ = deltaA >> 8; 3866059Samurai *cp++ = deltaA; 3876059Samurai BCOPY(new_seq, cp, deltaS); 3886059Samurai INCR(sls_compressed) 3896059Samurai return (TYPE_COMPRESSED_TCP); 3906059Samurai 3916059Samurai /* 3926059Samurai * Update connection state cs & send uncompressed packet ('uncompressed' 3936059Samurai * means a regular ip/tcp packet but with the 'conversation id' we hope 3946059Samurai * to use on future compressed packets in the protocol field). 3956059Samurai */ 3966059Samuraiuncompressed: 3976059Samurai BCOPY(ip, &cs->cs_ip, hlen); 3986059Samurai ip->ip_p = cs->cs_id; 3996059Samurai comp->last_xmit = cs->cs_id; 4006059Samurai return (TYPE_UNCOMPRESSED_TCP); 4016059Samurai} 4026059Samurai 4036059Samurai 4046059Samuraiint 4056059Samuraisl_uncompress_tcp(bufp, len, type, comp) 4066059Samurai u_char **bufp; 4076059Samurai int len; 4086059Samurai u_int type; 4096059Samurai struct slcompress *comp; 4106059Samurai{ 4116059Samurai register u_char *cp; 4126059Samurai register u_int hlen, changes; 4136059Samurai register struct tcphdr *th; 4146059Samurai register struct cstate *cs; 4156059Samurai register struct ip *ip; 4166059Samurai 4176059Samurai switch (type) { 4186059Samurai 4196059Samurai case TYPE_UNCOMPRESSED_TCP: 4206059Samurai ip = (struct ip *) *bufp; 4216059Samurai if (ip->ip_p >= MAX_STATES) 4226059Samurai goto bad; 4236059Samurai cs = &comp->rstate[comp->last_recv = ip->ip_p]; 4246059Samurai comp->flags &=~ SLF_TOSS; 4256059Samurai ip->ip_p = IPPROTO_TCP; 42615190Sdg /* 42715190Sdg * Calculate the size of the TCP/IP header and make sure that 42815190Sdg * we don't overflow the space we have available for it. 42915190Sdg */ 43015190Sdg hlen = ip->ip_hl << 2; 43115190Sdg if (hlen + sizeof(struct tcphdr) > len) 43215190Sdg goto bad; 43315193Sdg th = (struct tcphdr *)&((char *)ip)[hlen]; 43415190Sdg hlen += THOFFSET(th) << 2; 43515190Sdg if (hlen > MAX_HDR) 43615190Sdg goto bad; 4376059Samurai BCOPY(ip, &cs->cs_ip, hlen); 4386059Samurai cs->cs_ip.ip_sum = 0; 4396059Samurai cs->cs_hlen = hlen; 4406059Samurai INCR(sls_uncompressedin) 4416059Samurai return (len); 4426059Samurai 4436059Samurai default: 4446059Samurai goto bad; 4456059Samurai 4466059Samurai case TYPE_COMPRESSED_TCP: 4476059Samurai break; 4486059Samurai } 4496059Samurai /* We've got a compressed packet. */ 4506059Samurai INCR(sls_compressedin) 4516059Samurai cp = *bufp; 4526059Samurai changes = *cp++; 45326516Sbrian LogPrintf(LogDEBUG, "compressed: changes = %02x\n", changes); 4546059Samurai if (changes & NEW_C) { 4556059Samurai /* Make sure the state index is in range, then grab the state. 4566059Samurai * If we have a good state index, clear the 'discard' flag. */ 4576735Samurai if (*cp >= MAX_STATES || comp->last_recv == 255) 4586059Samurai goto bad; 4596059Samurai 4606059Samurai comp->flags &=~ SLF_TOSS; 4616059Samurai comp->last_recv = *cp++; 4626059Samurai } else { 4636059Samurai /* this packet has an implicit state index. If we've 4646059Samurai * had a line error since the last time we got an 4656059Samurai * explicit state index, we have to toss the packet. */ 4666059Samurai if (comp->flags & SLF_TOSS) { 4676059Samurai INCR(sls_tossed) 4686059Samurai return (0); 4696059Samurai } 4706059Samurai } 4716059Samurai cs = &comp->rstate[comp->last_recv]; 4726059Samurai hlen = cs->cs_ip.ip_hl << 2; 4736059Samurai th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; 4746059Samurai th->th_sum = htons((*cp << 8) | cp[1]); 4756059Samurai cp += 2; 4766059Samurai if (changes & TCP_PUSH_BIT) 4776059Samurai th->th_flags |= TH_PUSH; 4786059Samurai else 4796059Samurai th->th_flags &=~ TH_PUSH; 4806059Samurai 4816059Samurai switch (changes & SPECIALS_MASK) { 4826059Samurai case SPECIAL_I: 4836059Samurai { 4846059Samurai register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; 4856059Samurai th->th_ack = htonl(ntohl(th->th_ack) + i); 4866059Samurai th->th_seq = htonl(ntohl(th->th_seq) + i); 4876059Samurai } 4886059Samurai break; 4896059Samurai 4906059Samurai case SPECIAL_D: 4916059Samurai th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) 4926059Samurai - cs->cs_hlen); 4936059Samurai break; 4946059Samurai 4956059Samurai default: 4966059Samurai if (changes & NEW_U) { 4976059Samurai th->th_flags |= TH_URG; 4986059Samurai DECODEU(th->th_urp) 4996059Samurai } else 5006059Samurai th->th_flags &=~ TH_URG; 5016059Samurai if (changes & NEW_W) 5026059Samurai DECODES(th->th_win) 5036059Samurai if (changes & NEW_A) 5046059Samurai DECODEL(th->th_ack) 5056059Samurai if (changes & NEW_S) { 50626516Sbrian LogPrintf(LogDEBUG, "NEW_S: %02x, %02x, %02x\n", 50726516Sbrian *cp, cp[1], cp[2]); 5086059Samurai DECODEL(th->th_seq) 5096059Samurai } 5106059Samurai break; 5116059Samurai } 5126059Samurai if (changes & NEW_I) { 5136059Samurai DECODES(cs->cs_ip.ip_id) 5146059Samurai } else 5156059Samurai cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1); 5166059Samurai 51726516Sbrian LogPrintf(LogDEBUG, "Uncompress: id = %04x, seq = %08x\n", 51826516Sbrian cs->cs_ip.ip_id, ntohl(th->th_seq)); 51926516Sbrian 5206059Samurai /* 5216059Samurai * At this point, cp points to the first byte of data in the 5226059Samurai * packet. If we're not aligned on a 4-byte boundary, copy the 5236059Samurai * data down so the ip & tcp headers will be aligned. Then back up 5246059Samurai * cp by the tcp/ip header length to make room for the reconstructed 5256059Samurai * header (we assume the packet we were handed has enough space to 5266059Samurai * prepend 128 bytes of header). Adjust the length to account for 5276059Samurai * the new header & fill in the IP total length. 5286059Samurai */ 5296059Samurai len -= (cp - *bufp); 5306059Samurai if (len < 0) 5316059Samurai /* we must have dropped some characters (crc should detect 5326059Samurai * this but the old slip framing won't) */ 5336059Samurai goto bad; 5346059Samurai 5356059Samurai#ifdef notdef 5366059Samurai if ((int)cp & 3) { 5376059Samurai if (len > 0) 5386059Samurai (void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len); 5396059Samurai cp = (u_char *)((int)cp &~ 3); 5406059Samurai } 5416059Samurai#endif 5426059Samurai 5436059Samurai cp -= cs->cs_hlen; 5446059Samurai len += cs->cs_hlen; 5456059Samurai cs->cs_ip.ip_len = htons(len); 5466059Samurai BCOPY(&cs->cs_ip, cp, cs->cs_hlen); 5476059Samurai *bufp = cp; 5486059Samurai 5496059Samurai /* recompute the ip header checksum */ 5506059Samurai { 5516059Samurai register u_short *bp = (u_short *)cp; 5526059Samurai for (changes = 0; hlen > 0; hlen -= 2) 5536059Samurai changes += *bp++; 5546059Samurai changes = (changes & 0xffff) + (changes >> 16); 5556059Samurai changes = (changes & 0xffff) + (changes >> 16); 5566059Samurai ((struct ip *)cp)->ip_sum = ~ changes; 5576059Samurai } 5586059Samurai return (len); 5596059Samuraibad: 5606059Samurai comp->flags |= SLF_TOSS; 5616059Samurai INCR(sls_errorin) 5626059Samurai return (0); 5636059Samurai} 5646059Samurai 5656059Samuraiint 5666059SamuraiReportCompress() 5676059Samurai{ 56826516Sbrian if (!VarTerm) 56926516Sbrian return 1; 57026516Sbrian 57126516Sbrian fprintf(VarTerm, "Out: %d (compress) / %d (total)", 5726059Samurai slstat.sls_compressed, slstat.sls_packets); 57326516Sbrian fprintf(VarTerm, " %d (miss) / %d (search)\n", 5746059Samurai slstat.sls_misses, slstat.sls_searches); 57526516Sbrian fprintf(VarTerm, "In: %d (compress), %d (uncompress)", 5766059Samurai slstat.sls_compressedin, slstat.sls_uncompressedin); 57726516Sbrian fprintf(VarTerm, " %d (error), %d (tossed)\n", 5786059Samurai slstat.sls_errorin, slstat.sls_tossed); 57926516Sbrian return 0; 5806059Samurai} 581