1139979Sbrian/*- 2139979Sbrian * Copyright (c) 1989, 1993, 1994 3139979Sbrian * The Regents of the University of California. All rights reserved. 4139979Sbrian * 5139979Sbrian * Redistribution and use in source and binary forms, with or without 6139979Sbrian * modification, are permitted provided that the following conditions 7139979Sbrian * are met: 8139979Sbrian * 1. Redistributions of source code must retain the above copyright 9139979Sbrian * notice, this list of conditions and the following disclaimer. 10139979Sbrian * 2. Redistributions in binary form must reproduce the above copyright 11139979Sbrian * notice, this list of conditions and the following disclaimer in the 12139979Sbrian * documentation and/or other materials provided with the distribution. 13139979Sbrian * 3. Neither the name of the University nor the names of its contributors 14139979Sbrian * may be used to endorse or promote products derived from this software 15139979Sbrian * without specific prior written permission. 16139979Sbrian * 17139979Sbrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18139979Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19139979Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20139979Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21139979Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22139979Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23139979Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24139979Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25139979Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26139979Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27139979Sbrian * SUCH DAMAGE. 28139979Sbrian * 29139979Sbrian * @(#)slcompress.c 8.2 (Berkeley) 4/16/94 30139979Sbrian */ 31139979Sbrian 326059Samurai/* 336059Samurai * Routines to compress and uncompess tcp packets (for transmission 346059Samurai * over low speed serial lines. 356059Samurai * 36139979Sbrian * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: 37139979Sbrian * - Initial distribution. 386059Samurai * 3950479Speter * $FreeBSD$ 406059Samurai */ 4128679Sbrian 4243313Sbrian#include <sys/param.h> 436059Samurai#include <netinet/in_systm.h> 446059Samurai#include <netinet/in.h> 456059Samurai#include <netinet/tcp.h> 466059Samurai#include <netinet/ip.h> 4781634Sbrian#include <sys/socket.h> 4836285Sbrian#include <sys/un.h> 4930715Sbrian 50102500Sbrian#include <stdarg.h> 5130715Sbrian#include <stdio.h> 5230715Sbrian#include <string.h> 5336285Sbrian#include <termios.h> 5430715Sbrian 5546686Sbrian#include "layer.h" 5637009Sbrian#include "defs.h" 5731343Sbrian#include "command.h" 5830715Sbrian#include "mbuf.h" 5930715Sbrian#include "log.h" 606059Samurai#include "slcompress.h" 6136285Sbrian#include "descriptor.h" 6236285Sbrian#include "prompt.h" 6336285Sbrian#include "timer.h" 6436285Sbrian#include "fsm.h" 6536285Sbrian#include "throughput.h" 6636285Sbrian#include "iplist.h" 6738557Sbrian#include "lqr.h" 6838557Sbrian#include "hdlc.h" 6981634Sbrian#include "ncpaddr.h" 7036285Sbrian#include "ipcp.h" 7136285Sbrian#include "filter.h" 7236285Sbrian#include "lcp.h" 7336285Sbrian#include "ccp.h" 7436285Sbrian#include "link.h" 7536285Sbrian#include "mp.h" 7643313Sbrian#ifndef NORADIUS 7743313Sbrian#include "radius.h" 7843313Sbrian#endif 7981634Sbrian#include "ipv6cp.h" 8081634Sbrian#include "ncp.h" 8136285Sbrian#include "bundle.h" 826059Samurai 836059Samuraivoid 8446828Sbriansl_compress_init(struct slcompress *comp, int max_state) 856059Samurai{ 8628679Sbrian register u_int i; 8728679Sbrian register struct cstate *tstate = comp->tstate; 886059Samurai 8931962Sbrian memset(comp, '\0', sizeof *comp); 9030187Sbrian for (i = max_state; i > 0; --i) { 9128679Sbrian tstate[i].cs_id = i; 9228679Sbrian tstate[i].cs_next = &tstate[i - 1]; 9328679Sbrian } 9430187Sbrian tstate[0].cs_next = &tstate[max_state]; 9528679Sbrian tstate[0].cs_id = 0; 9628679Sbrian comp->last_cs = &tstate[0]; 9728679Sbrian comp->last_recv = 255; 9828679Sbrian comp->last_xmit = 255; 9928679Sbrian comp->flags = SLF_TOSS; 1006059Samurai} 1016059Samurai 1026059Samurai 1036059Samurai/* ENCODE encodes a number that is known to be non-zero. ENCODEZ 10437189Sbrian * checks for zero (since zero has to be encoded in the 32-bit, 3 byte 1056059Samurai * form). 1066059Samurai */ 1076059Samurai#define ENCODE(n) { \ 1086059Samurai if ((u_short)(n) >= 256) { \ 1096059Samurai *cp++ = 0; \ 1106059Samurai cp[1] = (n); \ 1116059Samurai cp[0] = (n) >> 8; \ 1126059Samurai cp += 2; \ 1136059Samurai } else { \ 1146059Samurai *cp++ = (n); \ 1156059Samurai } \ 1166059Samurai} 1176059Samurai#define ENCODEZ(n) { \ 1186059Samurai if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ 1196059Samurai *cp++ = 0; \ 1206059Samurai cp[1] = (n); \ 1216059Samurai cp[0] = (n) >> 8; \ 1226059Samurai cp += 2; \ 1236059Samurai } else { \ 1246059Samurai *cp++ = (n); \ 1256059Samurai } \ 1266059Samurai} 1276059Samurai 1286059Samurai#define DECODEL(f) { \ 1296059Samurai if (*cp == 0) {\ 1306059Samurai (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \ 1316059Samurai cp += 3; \ 1326059Samurai } else { \ 13337189Sbrian (f) = htonl(ntohl(f) + (u_int32_t)*cp++); \ 1346059Samurai } \ 1356059Samurai} 1366059Samurai 1376059Samurai#define DECODES(f) { \ 1386059Samurai if (*cp == 0) {\ 1396059Samurai (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \ 1406059Samurai cp += 3; \ 1416059Samurai } else { \ 14237189Sbrian (f) = htons(ntohs(f) + (u_int32_t)*cp++); \ 1436059Samurai } \ 1446059Samurai} 1456059Samurai 1466059Samurai#define DECODEU(f) { \ 1476059Samurai if (*cp == 0) {\ 1486059Samurai (f) = htons((cp[1] << 8) | cp[2]); \ 1496059Samurai cp += 3; \ 1506059Samurai } else { \ 15137189Sbrian (f) = htons((u_int32_t)*cp++); \ 1526059Samurai } \ 1536059Samurai} 1546059Samurai 1556059Samurai 1566059Samuraiu_char 15728679Sbriansl_compress_tcp(struct mbuf * m, 15828679Sbrian struct ip * ip, 15936285Sbrian struct slcompress *comp, 16036285Sbrian struct slstat *slstat, 16128679Sbrian int compress_cid) 1626059Samurai{ 16328679Sbrian register struct cstate *cs = comp->last_cs->cs_next; 16428679Sbrian register u_int hlen = ip->ip_hl; 16528679Sbrian register struct tcphdr *oth; 16628679Sbrian register struct tcphdr *th; 16728679Sbrian register u_int deltaS, deltaA; 16828679Sbrian register u_int changes = 0; 16928679Sbrian u_char new_seq[16]; 17028679Sbrian register u_char *cp = new_seq; 1716059Samurai 17228679Sbrian /* 17328679Sbrian * Bail if this is an IP fragment or if the TCP packet isn't `compressible' 17428679Sbrian * (i.e., ACK isn't set or some other control bit is set). (We assume that 17528679Sbrian * the caller has already made sure the packet is IP proto TCP). 17628679Sbrian */ 17754912Sbrian if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40) { 17858042Sbrian log_Printf(LogDEBUG, "??? 1 ip_off = %x, m_len = %lu\n", 17958042Sbrian ip->ip_off, (unsigned long)m->m_len); 18036285Sbrian log_DumpBp(LogDEBUG, "", m); 18128679Sbrian return (TYPE_IP); 18228679Sbrian } 18328679Sbrian th = (struct tcphdr *) & ((int *) ip)[hlen]; 18428679Sbrian if ((th->th_flags & (TH_SYN | TH_FIN | TH_RST | TH_ACK)) != TH_ACK) { 18536285Sbrian log_Printf(LogDEBUG, "??? 2 th_flags = %x\n", th->th_flags); 18636285Sbrian log_DumpBp(LogDEBUG, "", m); 18728679Sbrian return (TYPE_IP); 18828679Sbrian } 1896059Samurai 19028679Sbrian /* 19128679Sbrian * Packet is compressible -- we're going to send either a COMPRESSED_TCP or 19228679Sbrian * UNCOMPRESSED_TCP packet. Either way we need to locate (or create) the 19328679Sbrian * connection state. Special case the most recently used connection since 19428679Sbrian * it's most likely to be used again & we don't have to do any reordering 19528679Sbrian * if it's used. 19628679Sbrian */ 19736285Sbrian slstat->sls_packets++; 19836285Sbrian if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || 19936285Sbrian ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || 20036285Sbrian *(int *) th != ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl]) { 2016059Samurai 20228679Sbrian /* 20328679Sbrian * Wasn't the first -- search for it. 20498243Sbrian * 20528679Sbrian * States are kept in a circularly linked list with last_cs pointing to the 20628679Sbrian * end of the list. The list is kept in lru order by moving a state to 20728679Sbrian * the head of the list whenever it is referenced. Since the list is 20828679Sbrian * short and, empirically, the connection we want is almost always near 20928679Sbrian * the front, we locate states via linear search. If we don't find a 21028679Sbrian * state for the datagram, the oldest state is (re-)used. 21128679Sbrian */ 21228679Sbrian register struct cstate *lcs; 21328679Sbrian register struct cstate *lastcs = comp->last_cs; 2146059Samurai 21528679Sbrian do { 21628679Sbrian lcs = cs; 21728679Sbrian cs = cs->cs_next; 21836285Sbrian slstat->sls_searches++; 21936285Sbrian if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr 22036285Sbrian && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr 22136285Sbrian && *(int *) th == ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl]) 22228679Sbrian goto found; 22328679Sbrian } while (cs != lastcs); 2246059Samurai 22528679Sbrian /* 22628679Sbrian * Didn't find it -- re-use oldest cstate. Send an uncompressed packet 22728679Sbrian * that tells the other side what connection number we're using for this 22828679Sbrian * conversation. Note that since the state list is circular, the oldest 22928679Sbrian * state points to the newest and we only need to set last_cs to update 23028679Sbrian * the lru linkage. 23128679Sbrian */ 23236285Sbrian slstat->sls_misses++; 23328679Sbrian comp->last_cs = lcs; 2346059Samurai#define THOFFSET(th) (th->th_off) 23528679Sbrian hlen += th->th_off; 23628679Sbrian hlen <<= 2; 23754912Sbrian if (hlen > m->m_len) 23828679Sbrian return (TYPE_IP); 23928679Sbrian goto uncompressed; 2406059Samurai 24128679Sbrianfound: 2426059Samurai 24328679Sbrian /* 24428679Sbrian * Found it -- move to the front on the connection list. 24528679Sbrian */ 24628679Sbrian if (cs == lastcs) 24728679Sbrian comp->last_cs = lcs; 24828679Sbrian else { 24928679Sbrian lcs->cs_next = cs->cs_next; 25028679Sbrian cs->cs_next = lastcs->cs_next; 25128679Sbrian lastcs->cs_next = cs; 25228679Sbrian } 25328679Sbrian } 2546059Samurai 25528679Sbrian /* 25628679Sbrian * Make sure that only what we expect to change changed. The first line of 25728679Sbrian * the `if' checks the IP protocol version, header length & type of 25828679Sbrian * service. The 2nd line checks the "Don't fragment" bit. The 3rd line 25928679Sbrian * checks the time-to-live and protocol (the protocol check is unnecessary 26028679Sbrian * but costless). The 4th line checks the TCP header length. The 5th line 26128679Sbrian * checks IP options, if any. The 6th line checks TCP options, if any. If 26228679Sbrian * any of these things are different between the previous & current 26328679Sbrian * datagram, we send the current datagram `uncompressed'. 26428679Sbrian */ 26528679Sbrian oth = (struct tcphdr *) & ((int *) &cs->cs_ip)[hlen]; 26628679Sbrian deltaS = hlen; 26728679Sbrian hlen += th->th_off; 26828679Sbrian hlen <<= 2; 26954912Sbrian if (hlen > m->m_len) 27028679Sbrian return (TYPE_IP); 2716059Samurai 27228679Sbrian if (((u_short *) ip)[0] != ((u_short *) & cs->cs_ip)[0] || 27328679Sbrian ((u_short *) ip)[3] != ((u_short *) & cs->cs_ip)[3] || 27428679Sbrian ((u_short *) ip)[4] != ((u_short *) & cs->cs_ip)[4] || 27528679Sbrian THOFFSET(th) != THOFFSET(oth) || 27628679Sbrian (deltaS > 5 && 27730715Sbrian memcmp(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || 27828679Sbrian (THOFFSET(th) > 5 && 27930715Sbrian memcmp(th + 1, oth + 1, (THOFFSET(th) - 5) << 2))) { 28028679Sbrian goto uncompressed; 28128679Sbrian } 2826059Samurai 28328679Sbrian /* 28428679Sbrian * Figure out which of the changing fields changed. The receiver expects 28528679Sbrian * changes in the order: urgent, window, ack, seq (the order minimizes the 28628679Sbrian * number of temporaries needed in this section of code). 28728679Sbrian */ 28828679Sbrian if (th->th_flags & TH_URG) { 28928679Sbrian deltaS = ntohs(th->th_urp); 29028679Sbrian ENCODEZ(deltaS); 29128679Sbrian changes |= NEW_U; 29228679Sbrian } else if (th->th_urp != oth->th_urp) { 2936059Samurai 29428679Sbrian /* 29528679Sbrian * argh! URG not set but urp changed -- a sensible implementation should 29628679Sbrian * never do this but RFC793 doesn't prohibit the change so we have to 29728679Sbrian * deal with it. 29828679Sbrian */ 29928679Sbrian goto uncompressed; 30028679Sbrian } 30128679Sbrian deltaS = (u_short) (ntohs(th->th_win) - ntohs(oth->th_win)); 30228679Sbrian if (deltaS) { 30328679Sbrian ENCODE(deltaS); 30428679Sbrian changes |= NEW_W; 30528679Sbrian } 30628679Sbrian deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack); 30728679Sbrian if (deltaA) { 30828679Sbrian if (deltaA > 0xffff) { 30928679Sbrian goto uncompressed; 31028679Sbrian } 31128679Sbrian ENCODE(deltaA); 31228679Sbrian changes |= NEW_A; 31328679Sbrian } 31428679Sbrian deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq); 31528679Sbrian if (deltaS) { 31628679Sbrian if (deltaS > 0xffff) { 31728679Sbrian goto uncompressed; 31828679Sbrian } 31928679Sbrian ENCODE(deltaS); 32028679Sbrian changes |= NEW_S; 32128679Sbrian } 32228679Sbrian switch (changes) { 3236059Samurai 32428679Sbrian case 0: 3256059Samurai 32628679Sbrian /* 32728679Sbrian * Nothing changed. If this packet contains data and the last one didn't, 32828679Sbrian * this is probably a data packet following an ack (normal on an 32928679Sbrian * interactive connection) and we send it compressed. Otherwise it's 33028679Sbrian * probably a retransmit, retransmitted ack or window probe. Send it 33128679Sbrian * uncompressed in case the other side missed the compressed version. 33228679Sbrian */ 33328679Sbrian if (ip->ip_len != cs->cs_ip.ip_len && 33428679Sbrian ntohs(cs->cs_ip.ip_len) == hlen) 33528679Sbrian break; 3366059Samurai 337102413Scharnier /* FALLTHROUGH */ 3386059Samurai 33928679Sbrian case SPECIAL_I: 34028679Sbrian case SPECIAL_D: 3416059Samurai 34228679Sbrian /* 34328679Sbrian * actual changes match one of our special case encodings -- send packet 34428679Sbrian * uncompressed. 34528679Sbrian */ 34628679Sbrian goto uncompressed; 3476059Samurai 34828679Sbrian case NEW_S | NEW_A: 34928679Sbrian if (deltaS == deltaA && 35028679Sbrian deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { 35128679Sbrian /* special case for echoed terminal traffic */ 35228679Sbrian changes = SPECIAL_I; 35328679Sbrian cp = new_seq; 35428679Sbrian } 35528679Sbrian break; 3566059Samurai 35728679Sbrian case NEW_S: 35828679Sbrian if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { 35928679Sbrian /* special case for data xfer */ 36028679Sbrian changes = SPECIAL_D; 36128679Sbrian cp = new_seq; 36228679Sbrian } 36328679Sbrian break; 36428679Sbrian } 3656059Samurai 36628679Sbrian deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); 36728679Sbrian if (deltaS != 1) { 36828679Sbrian ENCODEZ(deltaS); 36928679Sbrian changes |= NEW_I; 37028679Sbrian } 37128679Sbrian if (th->th_flags & TH_PUSH) 37228679Sbrian changes |= TCP_PUSH_BIT; 3736059Samurai 37428679Sbrian /* 37528679Sbrian * Grab the cksum before we overwrite it below. Then update our state with 37628679Sbrian * this packet's header. 37728679Sbrian */ 37828679Sbrian deltaA = ntohs(th->th_sum); 37930715Sbrian memcpy(&cs->cs_ip, ip, hlen); 3806059Samurai 38128679Sbrian /* 38228679Sbrian * We want to use the original packet as our compressed packet. (cp - 38328679Sbrian * new_seq) is the number of bytes we need for compressed sequence numbers. 38428679Sbrian * In addition we need one byte for the change mask, one for the connection 38528679Sbrian * id and two for the tcp checksum. So, (cp - new_seq) + 4 bytes of header 38628679Sbrian * are needed. hlen is how many bytes of the original packet to toss so 38728679Sbrian * subtract the two to get the new packet size. 38828679Sbrian */ 38928679Sbrian deltaS = cp - new_seq; 39028679Sbrian cp = (u_char *) ip; 39128679Sbrian 39228679Sbrian /* 39328679Sbrian * Since fastq traffic can jump ahead of the background traffic, we don't 39428679Sbrian * know what order packets will go on the line. In this case, we always 39528679Sbrian * send a "new" connection id so the receiver state stays synchronized. 39628679Sbrian */ 39730187Sbrian if (comp->last_xmit == cs->cs_id && compress_cid) { 39828679Sbrian hlen -= deltaS + 3; 39928679Sbrian cp += hlen; 40028679Sbrian *cp++ = changes; 40130187Sbrian } else { 40228679Sbrian comp->last_xmit = cs->cs_id; 40328679Sbrian hlen -= deltaS + 4; 40428679Sbrian cp += hlen; 40528679Sbrian *cp++ = changes | NEW_C; 40628679Sbrian *cp++ = cs->cs_id; 40728679Sbrian } 40854912Sbrian m->m_len -= hlen; 40954912Sbrian m->m_offset += hlen; 41028679Sbrian *cp++ = deltaA >> 8; 41128679Sbrian *cp++ = deltaA; 41230715Sbrian memcpy(cp, new_seq, deltaS); 41336285Sbrian slstat->sls_compressed++; 41436285Sbrian return (TYPE_COMPRESSED_TCP); 4156059Samurai 41628679Sbrian /* 41728679Sbrian * Update connection state cs & send uncompressed packet ('uncompressed' 41828679Sbrian * means a regular ip/tcp packet but with the 'conversation id' we hope to 41928679Sbrian * use on future compressed packets in the protocol field). 42028679Sbrian */ 4216059Samuraiuncompressed: 42230715Sbrian memcpy(&cs->cs_ip, ip, hlen); 42328679Sbrian ip->ip_p = cs->cs_id; 42428679Sbrian comp->last_xmit = cs->cs_id; 42528679Sbrian return (TYPE_UNCOMPRESSED_TCP); 4266059Samurai} 4276059Samurai 4286059Samurai 4296059Samuraiint 43036960Sbriansl_uncompress_tcp(u_char ** bufp, int len, u_int type, struct slcompress *comp, 43136960Sbrian struct slstat *slstat, int max_state) 4326059Samurai{ 43328679Sbrian register u_char *cp; 43428679Sbrian register u_int hlen, changes; 43528679Sbrian register struct tcphdr *th; 43628679Sbrian register struct cstate *cs; 43728679Sbrian register struct ip *ip; 43852197Sbrian u_short *bp; 4396059Samurai 44028679Sbrian switch (type) { 4416059Samurai 44228679Sbrian case TYPE_UNCOMPRESSED_TCP: 44328679Sbrian ip = (struct ip *) * bufp; 44436960Sbrian if (ip->ip_p > max_state) 44528679Sbrian goto bad; 44628679Sbrian cs = &comp->rstate[comp->last_recv = ip->ip_p]; 44728679Sbrian comp->flags &= ~SLF_TOSS; 44828679Sbrian ip->ip_p = IPPROTO_TCP; 4496059Samurai 45028679Sbrian /* 45128679Sbrian * Calculate the size of the TCP/IP header and make sure that we don't 45228679Sbrian * overflow the space we have available for it. 45328679Sbrian */ 45428679Sbrian hlen = ip->ip_hl << 2; 455134789Sbrian if ((int)(hlen + sizeof(struct tcphdr)) > len) 45628679Sbrian goto bad; 45728679Sbrian th = (struct tcphdr *) & ((char *) ip)[hlen]; 45828679Sbrian hlen += THOFFSET(th) << 2; 45928679Sbrian if (hlen > MAX_HDR) 46028679Sbrian goto bad; 46130715Sbrian memcpy(&cs->cs_ip, ip, hlen); 46228679Sbrian cs->cs_hlen = hlen; 46336285Sbrian slstat->sls_uncompressedin++; 46436285Sbrian return (len); 4656059Samurai 46628679Sbrian default: 46728679Sbrian goto bad; 4686059Samurai 46928679Sbrian case TYPE_COMPRESSED_TCP: 47028679Sbrian break; 47128679Sbrian } 47245138Sbrian 47328679Sbrian /* We've got a compressed packet. */ 47436285Sbrian slstat->sls_compressedin++; 47536285Sbrian cp = *bufp; 47628679Sbrian changes = *cp++; 47736285Sbrian log_Printf(LogDEBUG, "compressed: changes = %02x\n", changes); 47845138Sbrian 47928679Sbrian if (changes & NEW_C) { 48028679Sbrian /* 48128679Sbrian * Make sure the state index is in range, then grab the state. If we have 48228679Sbrian * a good state index, clear the 'discard' flag. 48328679Sbrian */ 48446686Sbrian if (*cp > max_state || comp->last_recv == 255) 48528679Sbrian goto bad; 4866059Samurai 48728679Sbrian comp->flags &= ~SLF_TOSS; 48828679Sbrian comp->last_recv = *cp++; 48928679Sbrian } else { 49028679Sbrian /* 49128679Sbrian * this packet has an implicit state index. If we've had a line error 49228679Sbrian * since the last time we got an explicit state index, we have to toss 49328679Sbrian * the packet. 49428679Sbrian */ 49528679Sbrian if (comp->flags & SLF_TOSS) { 49636285Sbrian slstat->sls_tossed++; 49736285Sbrian return (0); 49828679Sbrian } 49928679Sbrian } 50028679Sbrian cs = &comp->rstate[comp->last_recv]; 50128679Sbrian hlen = cs->cs_ip.ip_hl << 2; 50228679Sbrian th = (struct tcphdr *) & ((u_char *) & cs->cs_ip)[hlen]; 50328679Sbrian th->th_sum = htons((*cp << 8) | cp[1]); 50428679Sbrian cp += 2; 50528679Sbrian if (changes & TCP_PUSH_BIT) 50628679Sbrian th->th_flags |= TH_PUSH; 50728679Sbrian else 50828679Sbrian th->th_flags &= ~TH_PUSH; 50928679Sbrian 51028679Sbrian switch (changes & SPECIALS_MASK) { 51128679Sbrian case SPECIAL_I: 51228679Sbrian { 51328679Sbrian register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; 51428679Sbrian 51528679Sbrian th->th_ack = htonl(ntohl(th->th_ack) + i); 51628679Sbrian th->th_seq = htonl(ntohl(th->th_seq) + i); 51728679Sbrian } 51828679Sbrian break; 51928679Sbrian 52028679Sbrian case SPECIAL_D: 52128679Sbrian th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) 52228679Sbrian - cs->cs_hlen); 52328679Sbrian break; 52428679Sbrian 52528679Sbrian default: 52628679Sbrian if (changes & NEW_U) { 52728679Sbrian th->th_flags |= TH_URG; 52828679Sbrian DECODEU(th->th_urp) 52928679Sbrian } else 53028679Sbrian th->th_flags &= ~TH_URG; 53128679Sbrian if (changes & NEW_W) 53228679Sbrian DECODES(th->th_win) 53328679Sbrian if (changes & NEW_A) 53428679Sbrian DECODEL(th->th_ack) 53528679Sbrian if (changes & NEW_S) { 53636285Sbrian log_Printf(LogDEBUG, "NEW_S: %02x, %02x, %02x\n", 53728679Sbrian *cp, cp[1], cp[2]); 53828679Sbrian DECODEL(th->th_seq) 5396059Samurai } 54028679Sbrian break; 54128679Sbrian } 54228679Sbrian if (changes & NEW_I) { 54328679Sbrian DECODES(cs->cs_ip.ip_id) 54428679Sbrian } else 54528679Sbrian cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1); 5466059Samurai 54736285Sbrian log_Printf(LogDEBUG, "Uncompress: id = %04x, seq = %08lx\n", 54836285Sbrian cs->cs_ip.ip_id, (u_long)ntohl(th->th_seq)); 54926516Sbrian 55028679Sbrian /* 55145138Sbrian * At this point, cp points to the first byte of data in the packet. 55245138Sbrian * Back up cp by the tcp/ip header length to make room for the 55345138Sbrian * reconstructed header (we assume the packet we were handed has enough 55445138Sbrian * space to prepend 128 bytes of header). Adjust the length to account 55545138Sbrian * for the new header & fill in the IP total length. 55628679Sbrian */ 55728679Sbrian len -= (cp - *bufp); 55828679Sbrian if (len < 0) 55928679Sbrian /* 56028679Sbrian * we must have dropped some characters (crc should detect this but the 56128679Sbrian * old slip framing won't) 56228679Sbrian */ 56328679Sbrian goto bad; 56428679Sbrian 56552197Sbrian *bufp = cp - cs->cs_hlen; 56628679Sbrian len += cs->cs_hlen; 56728679Sbrian cs->cs_ip.ip_len = htons(len); 5686059Samurai 56928679Sbrian /* recompute the ip header checksum */ 57052197Sbrian cs->cs_ip.ip_sum = 0; 57152197Sbrian bp = (u_short *)&cs->cs_ip; 57252197Sbrian for (changes = 0; hlen > 0; hlen -= 2) 57352197Sbrian changes += *bp++; 57452197Sbrian changes = (changes & 0xffff) + (changes >> 16); 57552197Sbrian changes = (changes & 0xffff) + (changes >> 16); 57652197Sbrian cs->cs_ip.ip_sum = ~changes; 57728679Sbrian 57852197Sbrian /* And copy the result into our buffer */ 57952197Sbrian memcpy(*bufp, &cs->cs_ip, cs->cs_hlen); 58045185Sbrian 58128679Sbrian return (len); 5826059Samuraibad: 58328679Sbrian comp->flags |= SLF_TOSS; 58436285Sbrian slstat->sls_errorin++; 58536285Sbrian return (0); 5866059Samurai} 5876059Samurai 5886059Samuraiint 58936285Sbriansl_Show(struct cmdargs const *arg) 5906059Samurai{ 59136285Sbrian prompt_Printf(arg->prompt, "VJ compression statistics:\n"); 59236285Sbrian prompt_Printf(arg->prompt, " Out: %d (compress) / %d (total)", 59336285Sbrian arg->bundle->ncp.ipcp.vj.slstat.sls_compressed, 59436285Sbrian arg->bundle->ncp.ipcp.vj.slstat.sls_packets); 59536285Sbrian prompt_Printf(arg->prompt, " %d (miss) / %d (search)\n", 59636285Sbrian arg->bundle->ncp.ipcp.vj.slstat.sls_misses, 59736285Sbrian arg->bundle->ncp.ipcp.vj.slstat.sls_searches); 59836285Sbrian prompt_Printf(arg->prompt, " In: %d (compress), %d (uncompress)", 59936285Sbrian arg->bundle->ncp.ipcp.vj.slstat.sls_compressedin, 60036285Sbrian arg->bundle->ncp.ipcp.vj.slstat.sls_uncompressedin); 60136285Sbrian prompt_Printf(arg->prompt, " %d (error), %d (tossed)\n", 60236285Sbrian arg->bundle->ncp.ipcp.vj.slstat.sls_errorin, 60336285Sbrian arg->bundle->ncp.ipcp.vj.slstat.sls_tossed); 60426516Sbrian return 0; 6056059Samurai} 606