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