slcompress.c revision 6059
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 * 206059Samurai * $Id:$ 216059Samurai * 226059Samurai * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: 236059Samurai * - Initial distribution. 246059Samurai */ 256059Samurai#ifndef lint 266059Samuraistatic char rcsid[] = "$Header"; 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" 356059Samurai 366059Samuraistruct slstat slstat; 376059Samurai 386059Samurai#define INCR(counter) slstat.counter++; 396059Samurai 406059Samurai#define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n)) 416059Samurai#define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n)) 426059Samurai#ifndef KERNEL 436059Samurai#define ovbcopy bcopy 446059Samurai#endif 456059Samurai 466059Samuraistatic int reason1, reason2, reason3, reason4, reason5; 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#ifdef DEBUG 1456059Samurai if ((ip->ip_off & htons(0x3fff)) || m->cnt < 40) { 1466059Samurai logprintf("??? 1 ip_off = %x, cnt = %d\n", ip->ip_off, m->cnt); 1476059Samurai DumpBp(m); 1486059Samurai return (TYPE_IP); 1496059Samurai } 1506059Samurai#else 1516059Samurai if ((ip->ip_off & htons(0x3fff)) || m->cnt < 40) 1526059Samurai return (TYPE_IP); 1536059Samurai#endif 1546059Samurai 1556059Samurai th = (struct tcphdr *)&((int *)ip)[hlen]; 1566059Samurai#ifdef DEBUG 1576059Samurai if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) { 1586059Samurai logprintf("??? 2 th_flags = %x\n", th->th_flags); 1596059Samurai DumpBp(m); 1606059Samurai return (TYPE_IP); 1616059Samurai } 1626059Samurai#else 1636059Samurai if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) 1646059Samurai return (TYPE_IP); 1656059Samurai#endif 1666059Samurai 1676059Samurai /* 1686059Samurai * Packet is compressible -- we're going to send either a 1696059Samurai * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need 1706059Samurai * to locate (or create) the connection state. Special case the 1716059Samurai * most recently used connection since it's most likely to be used 1726059Samurai * again & we don't have to do any reordering if it's used. 1736059Samurai */ 1746059Samurai INCR(sls_packets) 1756059Samurai if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || 1766059Samurai ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || 1776059Samurai *(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) { 1786059Samurai /* 1796059Samurai * Wasn't the first -- search for it. 1806059Samurai * 1816059Samurai * States are kept in a circularly linked list with 1826059Samurai * last_cs pointing to the end of the list. The 1836059Samurai * list is kept in lru order by moving a state to the 1846059Samurai * head of the list whenever it is referenced. Since 1856059Samurai * the list is short and, empirically, the connection 1866059Samurai * we want is almost always near the front, we locate 1876059Samurai * states via linear search. If we don't find a state 1886059Samurai * for the datagram, the oldest state is (re-)used. 1896059Samurai */ 1906059Samurai register struct cstate *lcs; 1916059Samurai register struct cstate *lastcs = comp->last_cs; 1926059Samurai 1936059Samurai do { 1946059Samurai lcs = cs; cs = cs->cs_next; 1956059Samurai INCR(sls_searches) 1966059Samurai if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr 1976059Samurai && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr 1986059Samurai && *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) 1996059Samurai goto found; 2006059Samurai } while (cs != lastcs); 2016059Samurai 2026059Samurai /* 2036059Samurai * Didn't find it -- re-use oldest cstate. Send an 2046059Samurai * uncompressed packet that tells the other side what 2056059Samurai * connection number we're using for this conversation. 2066059Samurai * Note that since the state list is circular, the oldest 2076059Samurai * state points to the newest and we only need to set 2086059Samurai * last_cs to update the lru linkage. 2096059Samurai */ 2106059Samurai INCR(sls_misses) 2116059Samurai comp->last_cs = lcs; 2126059Samurai#define THOFFSET(th) (th->th_off) 2136059Samurai hlen += th->th_off; 2146059Samurai hlen <<= 2; 2156059Samurai if (hlen > m->cnt) 2166059Samurai return(TYPE_IP); 2176059Samuraireason1++; 2186059Samurai goto uncompressed; 2196059Samurai 2206059Samurai found: 2216059Samurai /* 2226059Samurai * Found it -- move to the front on the connection list. 2236059Samurai */ 2246059Samurai if (cs == lastcs) 2256059Samurai comp->last_cs = lcs; 2266059Samurai else { 2276059Samurai lcs->cs_next = cs->cs_next; 2286059Samurai cs->cs_next = lastcs->cs_next; 2296059Samurai lastcs->cs_next = cs; 2306059Samurai } 2316059Samurai } 2326059Samurai 2336059Samurai /* 2346059Samurai * Make sure that only what we expect to change changed. The first 2356059Samurai * line of the `if' checks the IP protocol version, header length & 2366059Samurai * type of service. The 2nd line checks the "Don't fragment" bit. 2376059Samurai * The 3rd line checks the time-to-live and protocol (the protocol 2386059Samurai * check is unnecessary but costless). The 4th line checks the TCP 2396059Samurai * header length. The 5th line checks IP options, if any. The 6th 2406059Samurai * line checks TCP options, if any. If any of these things are 2416059Samurai * different between the previous & current datagram, we send the 2426059Samurai * current datagram `uncompressed'. 2436059Samurai */ 2446059Samurai oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen]; 2456059Samurai deltaS = hlen; 2466059Samurai hlen += th->th_off; 2476059Samurai hlen <<= 2; 2486059Samurai if (hlen > m->cnt) 2496059Samurai return(TYPE_IP); 2506059Samurai 2516059Samurai if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] || 2526059Samurai ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] || 2536059Samurai ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] || 2546059Samurai THOFFSET(th) != THOFFSET(oth) || 2556059Samurai (deltaS > 5 && 2566059Samurai BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || 2576059Samurai (THOFFSET(th) > 5 && 2586059Samurai BCMP(th + 1, oth + 1, (THOFFSET(th) - 5) << 2))) { 2596059Samuraireason2++; 2606059Samurai goto uncompressed; 2616059Samurai } 2626059Samurai 2636059Samurai /* 2646059Samurai * Figure out which of the changing fields changed. The 2656059Samurai * receiver expects changes in the order: urgent, window, 2666059Samurai * ack, seq (the order minimizes the number of temporaries 2676059Samurai * needed in this section of code). 2686059Samurai */ 2696059Samurai if (th->th_flags & TH_URG) { 2706059Samurai deltaS = ntohs(th->th_urp); 2716059Samurai ENCODEZ(deltaS); 2726059Samurai changes |= NEW_U; 2736059Samurai } else if (th->th_urp != oth->th_urp) { 2746059Samurai /* argh! URG not set but urp changed -- a sensible 2756059Samurai * implementation should never do this but RFC793 2766059Samurai * doesn't prohibit the change so we have to deal 2776059Samurai * with it. */ 2786059Samuraireason3++; 2796059Samurai goto uncompressed; 2806059Samurai } 2816059Samurai 2826059Samurai deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win)); 2836059Samurai if (deltaS) { 2846059Samurai ENCODE(deltaS); 2856059Samurai changes |= NEW_W; 2866059Samurai } 2876059Samurai 2886059Samurai deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack); 2896059Samurai if (deltaA) { 2906059Samurai if (deltaA > 0xffff) { 2916059Samuraireason4++; 2926059Samurai goto uncompressed; 2936059Samurai } 2946059Samurai ENCODE(deltaA); 2956059Samurai changes |= NEW_A; 2966059Samurai } 2976059Samurai 2986059Samurai deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq); 2996059Samurai if (deltaS) { 3006059Samurai if (deltaS > 0xffff) { 3016059Samurai reason4++; 3026059Samurai goto uncompressed; 3036059Samurai } 3046059Samurai ENCODE(deltaS); 3056059Samurai changes |= NEW_S; 3066059Samurai } 3076059Samurai 3086059Samurai switch(changes) { 3096059Samurai 3106059Samurai case 0: 3116059Samurai /* 3126059Samurai * Nothing changed. If this packet contains data and the 3136059Samurai * last one didn't, this is probably a data packet following 3146059Samurai * an ack (normal on an interactive connection) and we send 3156059Samurai * it compressed. Otherwise it's probably a retransmit, 3166059Samurai * retransmitted ack or window probe. Send it uncompressed 3176059Samurai * in case the other side missed the compressed version. 3186059Samurai */ 3196059Samurai if (ip->ip_len != cs->cs_ip.ip_len && 3206059Samurai ntohs(cs->cs_ip.ip_len) == hlen) 3216059Samurai break; 3226059Samurai 3236059Samurai /* (fall through) */ 3246059Samurai 3256059Samurai case SPECIAL_I: 3266059Samurai case SPECIAL_D: 3276059Samurai /* 3286059Samurai * actual changes match one of our special case encodings -- 3296059Samurai * send packet uncompressed. 3306059Samurai */ 3316059Samuraireason5++; 3326059Samurai goto uncompressed; 3336059Samurai 3346059Samurai case NEW_S|NEW_A: 3356059Samurai if (deltaS == deltaA && 3366059Samurai deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { 3376059Samurai /* special case for echoed terminal traffic */ 3386059Samurai changes = SPECIAL_I; 3396059Samurai cp = new_seq; 3406059Samurai } 3416059Samurai break; 3426059Samurai 3436059Samurai case NEW_S: 3446059Samurai if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { 3456059Samurai /* special case for data xfer */ 3466059Samurai changes = SPECIAL_D; 3476059Samurai cp = new_seq; 3486059Samurai } 3496059Samurai break; 3506059Samurai } 3516059Samurai 3526059Samurai deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); 3536059Samurai if (deltaS != 1) { 3546059Samurai ENCODEZ(deltaS); 3556059Samurai changes |= NEW_I; 3566059Samurai } 3576059Samurai if (th->th_flags & TH_PUSH) 3586059Samurai changes |= TCP_PUSH_BIT; 3596059Samurai /* 3606059Samurai * Grab the cksum before we overwrite it below. Then update our 3616059Samurai * state with this packet's header. 3626059Samurai */ 3636059Samurai deltaA = ntohs(th->th_sum); 3646059Samurai BCOPY(ip, &cs->cs_ip, hlen); 3656059Samurai 3666059Samurai /* 3676059Samurai * We want to use the original packet as our compressed packet. 3686059Samurai * (cp - new_seq) is the number of bytes we need for compressed 3696059Samurai * sequence numbers. In addition we need one byte for the change 3706059Samurai * mask, one for the connection id and two for the tcp checksum. 3716059Samurai * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how 3726059Samurai * many bytes of the original packet to toss so subtract the two to 3736059Samurai * get the new packet size. 3746059Samurai */ 3756059Samurai deltaS = cp - new_seq; 3766059Samurai cp = (u_char *)ip; 3776059Samurai 3786059Samurai /* 3796059Samurai * Since fastq traffic can jump ahead of the background traffic, 3806059Samurai * we don't know what order packets will go on the line. In this 3816059Samurai * case, we always send a "new" connection id so the receiver state 3826059Samurai * stays synchronized. 3836059Samurai */ 3846059Samurai#ifdef SL_NOFASTQ 3856059Samurai if (comp->last_xmit == cs->cs_id) { 3866059Samurai hlen -= deltaS + 3; 3876059Samurai cp += hlen; 3886059Samurai *cp++ = changes; 3896059Samurai } else 3906059Samurai#endif 3916059Samurai { 3926059Samurai comp->last_xmit = cs->cs_id; 3936059Samurai hlen -= deltaS + 4; 3946059Samurai cp += hlen; 3956059Samurai *cp++ = changes | NEW_C; 3966059Samurai *cp++ = cs->cs_id; 3976059Samurai } 3986059Samurai m->cnt -= hlen; 3996059Samurai m->offset += hlen; 4006059Samurai *cp++ = deltaA >> 8; 4016059Samurai *cp++ = deltaA; 4026059Samurai BCOPY(new_seq, cp, deltaS); 4036059Samurai INCR(sls_compressed) 4046059Samurai return (TYPE_COMPRESSED_TCP); 4056059Samurai 4066059Samurai /* 4076059Samurai * Update connection state cs & send uncompressed packet ('uncompressed' 4086059Samurai * means a regular ip/tcp packet but with the 'conversation id' we hope 4096059Samurai * to use on future compressed packets in the protocol field). 4106059Samurai */ 4116059Samuraiuncompressed: 4126059Samurai BCOPY(ip, &cs->cs_ip, hlen); 4136059Samurai ip->ip_p = cs->cs_id; 4146059Samurai comp->last_xmit = cs->cs_id; 4156059Samurai return (TYPE_UNCOMPRESSED_TCP); 4166059Samurai} 4176059Samurai 4186059Samurai 4196059Samuraiint 4206059Samuraisl_uncompress_tcp(bufp, len, type, comp) 4216059Samurai u_char **bufp; 4226059Samurai int len; 4236059Samurai u_int type; 4246059Samurai struct slcompress *comp; 4256059Samurai{ 4266059Samurai register u_char *cp; 4276059Samurai register u_int hlen, changes; 4286059Samurai register struct tcphdr *th; 4296059Samurai register struct cstate *cs; 4306059Samurai register struct ip *ip; 4316059Samurai 4326059Samurai switch (type) { 4336059Samurai 4346059Samurai case TYPE_UNCOMPRESSED_TCP: 4356059Samurai ip = (struct ip *) *bufp; 4366059Samurai if (ip->ip_p >= MAX_STATES) 4376059Samurai goto bad; 4386059Samurai cs = &comp->rstate[comp->last_recv = ip->ip_p]; 4396059Samurai comp->flags &=~ SLF_TOSS; 4406059Samurai ip->ip_p = IPPROTO_TCP; 4416059Samurai hlen = ip->ip_hl; 4426059Samurai th = (struct tcphdr *)&((int *)ip)[hlen]; 4436059Samurai hlen += THOFFSET(th); 4446059Samurai hlen <<= 2; 4456059Samurai BCOPY(ip, &cs->cs_ip, hlen); 4466059Samurai cs->cs_ip.ip_sum = 0; 4476059Samurai cs->cs_hlen = hlen; 4486059Samurai INCR(sls_uncompressedin) 4496059Samurai return (len); 4506059Samurai 4516059Samurai default: 4526059Samurai goto bad; 4536059Samurai 4546059Samurai case TYPE_COMPRESSED_TCP: 4556059Samurai break; 4566059Samurai } 4576059Samurai /* We've got a compressed packet. */ 4586059Samurai INCR(sls_compressedin) 4596059Samurai cp = *bufp; 4606059Samurai changes = *cp++; 4616059Samurai#ifdef DEBUG 4626059Samurai logprintf("compressed: changes = %02x\n", changes); 4636059Samurai#endif 4646059Samurai if (changes & NEW_C) { 4656059Samurai /* Make sure the state index is in range, then grab the state. 4666059Samurai * If we have a good state index, clear the 'discard' flag. */ 4676059Samurai if (*cp >= MAX_STATES) 4686059Samurai goto bad; 4696059Samurai 4706059Samurai comp->flags &=~ SLF_TOSS; 4716059Samurai comp->last_recv = *cp++; 4726059Samurai } else { 4736059Samurai /* this packet has an implicit state index. If we've 4746059Samurai * had a line error since the last time we got an 4756059Samurai * explicit state index, we have to toss the packet. */ 4766059Samurai if (comp->flags & SLF_TOSS) { 4776059Samurai INCR(sls_tossed) 4786059Samurai return (0); 4796059Samurai } 4806059Samurai } 4816059Samurai cs = &comp->rstate[comp->last_recv]; 4826059Samurai hlen = cs->cs_ip.ip_hl << 2; 4836059Samurai th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; 4846059Samurai th->th_sum = htons((*cp << 8) | cp[1]); 4856059Samurai cp += 2; 4866059Samurai if (changes & TCP_PUSH_BIT) 4876059Samurai th->th_flags |= TH_PUSH; 4886059Samurai else 4896059Samurai th->th_flags &=~ TH_PUSH; 4906059Samurai 4916059Samurai switch (changes & SPECIALS_MASK) { 4926059Samurai case SPECIAL_I: 4936059Samurai { 4946059Samurai register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; 4956059Samurai th->th_ack = htonl(ntohl(th->th_ack) + i); 4966059Samurai th->th_seq = htonl(ntohl(th->th_seq) + i); 4976059Samurai } 4986059Samurai break; 4996059Samurai 5006059Samurai case SPECIAL_D: 5016059Samurai th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) 5026059Samurai - cs->cs_hlen); 5036059Samurai break; 5046059Samurai 5056059Samurai default: 5066059Samurai if (changes & NEW_U) { 5076059Samurai th->th_flags |= TH_URG; 5086059Samurai DECODEU(th->th_urp) 5096059Samurai } else 5106059Samurai th->th_flags &=~ TH_URG; 5116059Samurai if (changes & NEW_W) 5126059Samurai DECODES(th->th_win) 5136059Samurai if (changes & NEW_A) 5146059Samurai DECODEL(th->th_ack) 5156059Samurai if (changes & NEW_S) { 5166059Samurai#ifdef DEBUG 5176059Samurai logprintf("NEW_S: %02x, %02x, %02x\r\n", *cp, cp[1], cp[2]); 5186059Samurai#endif 5196059Samurai DECODEL(th->th_seq) 5206059Samurai } 5216059Samurai break; 5226059Samurai } 5236059Samurai if (changes & NEW_I) { 5246059Samurai DECODES(cs->cs_ip.ip_id) 5256059Samurai } else 5266059Samurai cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1); 5276059Samurai#ifdef DEBUG 5286059Samurai logprintf("id = %04x, seq = %08x\r\n", cs->cs_ip.ip_id, ntohl(th->th_seq)); 5296059Samurai#endif 5306059Samurai 5316059Samurai /* 5326059Samurai * At this point, cp points to the first byte of data in the 5336059Samurai * packet. If we're not aligned on a 4-byte boundary, copy the 5346059Samurai * data down so the ip & tcp headers will be aligned. Then back up 5356059Samurai * cp by the tcp/ip header length to make room for the reconstructed 5366059Samurai * header (we assume the packet we were handed has enough space to 5376059Samurai * prepend 128 bytes of header). Adjust the length to account for 5386059Samurai * the new header & fill in the IP total length. 5396059Samurai */ 5406059Samurai len -= (cp - *bufp); 5416059Samurai if (len < 0) 5426059Samurai /* we must have dropped some characters (crc should detect 5436059Samurai * this but the old slip framing won't) */ 5446059Samurai goto bad; 5456059Samurai 5466059Samurai#ifdef notdef 5476059Samurai if ((int)cp & 3) { 5486059Samurai if (len > 0) 5496059Samurai (void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len); 5506059Samurai cp = (u_char *)((int)cp &~ 3); 5516059Samurai } 5526059Samurai#endif 5536059Samurai 5546059Samurai cp -= cs->cs_hlen; 5556059Samurai len += cs->cs_hlen; 5566059Samurai cs->cs_ip.ip_len = htons(len); 5576059Samurai BCOPY(&cs->cs_ip, cp, cs->cs_hlen); 5586059Samurai *bufp = cp; 5596059Samurai 5606059Samurai /* recompute the ip header checksum */ 5616059Samurai { 5626059Samurai register u_short *bp = (u_short *)cp; 5636059Samurai for (changes = 0; hlen > 0; hlen -= 2) 5646059Samurai changes += *bp++; 5656059Samurai changes = (changes & 0xffff) + (changes >> 16); 5666059Samurai changes = (changes & 0xffff) + (changes >> 16); 5676059Samurai ((struct ip *)cp)->ip_sum = ~ changes; 5686059Samurai } 5696059Samurai return (len); 5706059Samuraibad: 5716059Samurai comp->flags |= SLF_TOSS; 5726059Samurai INCR(sls_errorin) 5736059Samurai return (0); 5746059Samurai} 5756059Samurai 5766059Samuraiint 5776059SamuraiReportCompress() 5786059Samurai{ 5796059Samurai printf("Out: %d (compress) / %d (total)", 5806059Samurai slstat.sls_compressed, slstat.sls_packets); 5816059Samurai printf(" %d (miss) / %d (search)\n", 5826059Samurai slstat.sls_misses, slstat.sls_searches); 5836059Samurai printf("In: %d (compress), %d (uncompress)", 5846059Samurai slstat.sls_compressedin, slstat.sls_uncompressedin); 5856059Samurai printf(" %d (error), %d (tossed)\n", 5866059Samurai slstat.sls_errorin, slstat.sls_tossed); 5876059Samurai printf("%d, %d, %d, %d, %d\n", reason1, reason2, reason3, reason4, reason5); 5886059Samurai return(1); 5896059Samurai} 590