slcompress.c revision 98243
167754Smsmith/*
267754Smsmith * Routines to compress and uncompess tcp packets (for transmission
367754Smsmith * over low speed serial lines.
4129684Snjl *
567754Smsmith * Copyright (c) 1989 Regents of the University of California.
667754Smsmith * All rights reserved.
767754Smsmith *
867754Smsmith * Redistribution and use in source and binary forms are permitted
967754Smsmith * provided that the above copyright notice and this paragraph are
1067754Smsmith * duplicated in all such forms and that any documentation,
1167754Smsmith * advertising materials, and other materials related to such
12126372Snjl * distribution and use acknowledge that the software was developed
1370243Smsmith * by the University of California, Berkeley.  The name of the
1467754Smsmith * University may not be used to endorse or promote products derived
1567754Smsmith * from this software without specific prior written permission.
1667754Smsmith * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1767754Smsmith * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1867754Smsmith * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1967754Smsmith *
2067754Smsmith * $FreeBSD: head/usr.sbin/ppp/slcompress.c 98243 2002-06-15 08:03:30Z brian $
2167754Smsmith *
2267754Smsmith *	Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
2367754Smsmith *	- Initial distribution.
2467754Smsmith */
2567754Smsmith
2667754Smsmith#include <sys/param.h>
2767754Smsmith#include <netinet/in_systm.h>
2867754Smsmith#include <netinet/in.h>
2967754Smsmith#include <netinet/tcp.h>
3067754Smsmith#include <netinet/ip.h>
3167754Smsmith#include <sys/socket.h>
3267754Smsmith#include <sys/un.h>
3367754Smsmith
3467754Smsmith#include <stdio.h>
3567754Smsmith#include <string.h>
3667754Smsmith#include <termios.h>
3767754Smsmith
3867754Smsmith#include "layer.h"
3967754Smsmith#include "defs.h"
4067754Smsmith#include "command.h"
4167754Smsmith#include "mbuf.h"
4267754Smsmith#include "log.h"
4367754Smsmith#include "slcompress.h"
4467754Smsmith#include "descriptor.h"
4567754Smsmith#include "prompt.h"
4667754Smsmith#include "timer.h"
4767754Smsmith#include "fsm.h"
4867754Smsmith#include "throughput.h"
4967754Smsmith#include "iplist.h"
5067754Smsmith#include "lqr.h"
5167754Smsmith#include "hdlc.h"
5267754Smsmith#include "ncpaddr.h"
5367754Smsmith#include "ipcp.h"
5467754Smsmith#include "filter.h"
5567754Smsmith#include "lcp.h"
5667754Smsmith#include "ccp.h"
5767754Smsmith#include "link.h"
5867754Smsmith#include "mp.h"
5967754Smsmith#ifndef NORADIUS
6067754Smsmith#include "radius.h"
6167754Smsmith#endif
6267754Smsmith#include "ipv6cp.h"
6367754Smsmith#include "ncp.h"
6467754Smsmith#include "bundle.h"
6567754Smsmith
6667754Smsmithvoid
6767754Smsmithsl_compress_init(struct slcompress *comp, int max_state)
6867754Smsmith{
6967754Smsmith  register u_int i;
7067754Smsmith  register struct cstate *tstate = comp->tstate;
7167754Smsmith
7267754Smsmith  memset(comp, '\0', sizeof *comp);
7367754Smsmith  for (i = max_state; i > 0; --i) {
7467754Smsmith    tstate[i].cs_id = i;
7567754Smsmith    tstate[i].cs_next = &tstate[i - 1];
7667754Smsmith  }
7767754Smsmith  tstate[0].cs_next = &tstate[max_state];
7867754Smsmith  tstate[0].cs_id = 0;
7967754Smsmith  comp->last_cs = &tstate[0];
8067754Smsmith  comp->last_recv = 255;
8167754Smsmith  comp->last_xmit = 255;
8267754Smsmith  comp->flags = SLF_TOSS;
8367754Smsmith}
8467754Smsmith
8567754Smsmith
8667754Smsmith/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
8767754Smsmith * checks for zero (since zero has to be encoded in the 32-bit, 3 byte
8867754Smsmith * form).
8967754Smsmith */
9067754Smsmith#define ENCODE(n) { \
9167754Smsmith	if ((u_short)(n) >= 256) { \
9267754Smsmith		*cp++ = 0; \
9367754Smsmith		cp[1] = (n); \
9467754Smsmith		cp[0] = (n) >> 8; \
9567754Smsmith		cp += 2; \
9667754Smsmith	} else { \
9767754Smsmith		*cp++ = (n); \
9867754Smsmith	} \
9967754Smsmith}
10067754Smsmith#define ENCODEZ(n) { \
10167754Smsmith	if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
10267754Smsmith		*cp++ = 0; \
10367754Smsmith		cp[1] = (n); \
10467754Smsmith		cp[0] = (n) >> 8; \
10567754Smsmith		cp += 2; \
10667754Smsmith	} else { \
10767754Smsmith		*cp++ = (n); \
10867754Smsmith	} \
10967754Smsmith}
11067754Smsmith
11167754Smsmith#define DECODEL(f) { \
11267754Smsmith	if (*cp == 0) {\
11367754Smsmith		(f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
11467754Smsmith		cp += 3; \
11567754Smsmith	} else { \
11667754Smsmith		(f) = htonl(ntohl(f) + (u_int32_t)*cp++); \
11767754Smsmith	} \
11867754Smsmith}
11967754Smsmith
12067754Smsmith#define DECODES(f) { \
12167754Smsmith	if (*cp == 0) {\
12267754Smsmith		(f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
12367754Smsmith		cp += 3; \
12477424Smsmith	} else { \
12591116Smsmith		(f) = htons(ntohs(f) + (u_int32_t)*cp++); \
12667754Smsmith	} \
12767754Smsmith}
12867754Smsmith
12967754Smsmith#define DECODEU(f) { \
13067754Smsmith	if (*cp == 0) {\
13167754Smsmith		(f) = htons((cp[1] << 8) | cp[2]); \
13283174Smsmith		cp += 3; \
13367754Smsmith	} else { \
13467754Smsmith		(f) = htons((u_int32_t)*cp++); \
13567754Smsmith	} \
13683174Smsmith}
13767754Smsmith
13867754Smsmith
13967754Smsmithu_char
14067754Smsmithsl_compress_tcp(struct mbuf * m,
14167754Smsmith		struct ip * ip,
14284491Smsmith		struct slcompress *comp,
14367754Smsmith                struct slstat *slstat,
14467754Smsmith		int compress_cid)
14567754Smsmith{
14683174Smsmith  register struct cstate *cs = comp->last_cs->cs_next;
14791116Smsmith  register u_int hlen = ip->ip_hl;
14867754Smsmith  register struct tcphdr *oth;
14967754Smsmith  register struct tcphdr *th;
15080062Smsmith  register u_int deltaS, deltaA;
15167754Smsmith  register u_int changes = 0;
15267754Smsmith  u_char new_seq[16];
15367754Smsmith  register u_char *cp = new_seq;
15467754Smsmith
15567754Smsmith  /*
15682367Smsmith   * Bail if this is an IP fragment or if the TCP packet isn't `compressible'
15767754Smsmith   * (i.e., ACK isn't set or some other control bit is set).  (We assume that
15899146Siwasaki   * the caller has already made sure the packet is IP proto TCP).
15967754Smsmith   */
16091116Smsmith  if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40) {
16167754Smsmith    log_Printf(LogDEBUG, "??? 1 ip_off = %x, m_len = %lu\n",
16267754Smsmith	      ip->ip_off, (unsigned long)m->m_len);
16367754Smsmith    log_DumpBp(LogDEBUG, "", m);
16467754Smsmith    return (TYPE_IP);
16567754Smsmith  }
16667754Smsmith  th = (struct tcphdr *) & ((int *) ip)[hlen];
16767754Smsmith  if ((th->th_flags & (TH_SYN | TH_FIN | TH_RST | TH_ACK)) != TH_ACK) {
16867754Smsmith    log_Printf(LogDEBUG, "??? 2 th_flags = %x\n", th->th_flags);
16967754Smsmith    log_DumpBp(LogDEBUG, "", m);
17083174Smsmith    return (TYPE_IP);
17167754Smsmith  }
17267754Smsmith
17367754Smsmith  /*
17483174Smsmith   * Packet is compressible -- we're going to send either a COMPRESSED_TCP or
17567754Smsmith   * UNCOMPRESSED_TCP packet.  Either way we need to locate (or create) the
17667754Smsmith   * connection state.  Special case the most recently used connection since
17767754Smsmith   * it's most likely to be used again & we don't have to do any reordering
17867754Smsmith   * if it's used.
17967754Smsmith   */
18067754Smsmith  slstat->sls_packets++;
18167754Smsmith  if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
18267754Smsmith      ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
18367754Smsmith      *(int *) th != ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl]) {
18467754Smsmith
18567754Smsmith    /*
18667754Smsmith     * Wasn't the first -- search for it.
18791116Smsmith     *
18867754Smsmith     * States are kept in a circularly linked list with last_cs pointing to the
18983174Smsmith     * end of the list.  The list is kept in lru order by moving a state to
19091116Smsmith     * the head of the list whenever it is referenced.  Since the list is
19167754Smsmith     * short and, empirically, the connection we want is almost always near
19267754Smsmith     * the front, we locate states via linear search.  If we don't find a
19367754Smsmith     * state for the datagram, the oldest state is (re-)used.
19467754Smsmith     */
195115351Snjl    register struct cstate *lcs;
196115351Snjl    register struct cstate *lastcs = comp->last_cs;
19767754Smsmith
19867754Smsmith    do {
19967754Smsmith      lcs = cs;
20067754Smsmith      cs = cs->cs_next;
20167754Smsmith      slstat->sls_searches++;
20267754Smsmith      if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
20367754Smsmith	  && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
20467754Smsmith	  && *(int *) th == ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl])
205115351Snjl	goto found;
206115351Snjl    } while (cs != lastcs);
20767754Smsmith
20867754Smsmith    /*
20967754Smsmith     * Didn't find it -- re-use oldest cstate.  Send an uncompressed packet
21067754Smsmith     * that tells the other side what connection number we're using for this
21167754Smsmith     * conversation. Note that since the state list is circular, the oldest
21267754Smsmith     * state points to the newest and we only need to set last_cs to update
21367754Smsmith     * the lru linkage.
21467754Smsmith     */
215115351Snjl    slstat->sls_misses++;
216115351Snjl      comp->last_cs = lcs;
217115351Snjl#define	THOFFSET(th)	(th->th_off)
218115351Snjl    hlen += th->th_off;
219115351Snjl    hlen <<= 2;
220115351Snjl    if (hlen > m->m_len)
221115351Snjl      return (TYPE_IP);
222115351Snjl    goto uncompressed;
223115351Snjl
224115351Snjlfound:
225115351Snjl
226115351Snjl    /*
227115351Snjl     * Found it -- move to the front on the connection list.
22867754Smsmith     */
22967754Smsmith    if (cs == lastcs)
23067754Smsmith      comp->last_cs = lcs;
23182367Smsmith    else {
23267754Smsmith      lcs->cs_next = cs->cs_next;
23367754Smsmith      cs->cs_next = lastcs->cs_next;
23487031Smsmith      lastcs->cs_next = cs;
23567754Smsmith    }
23687031Smsmith  }
23780062Smsmith
23867754Smsmith  /*
23967754Smsmith   * Make sure that only what we expect to change changed. The first line of
24067754Smsmith   * the `if' checks the IP protocol version, header length & type of
24167754Smsmith   * service.  The 2nd line checks the "Don't fragment" bit. The 3rd line
242107325Siwasaki   * checks the time-to-live and protocol (the protocol check is unnecessary
24367754Smsmith   * but costless).  The 4th line checks the TCP header length.  The 5th line
24467754Smsmith   * checks IP options, if any.  The 6th line checks TCP options, if any.  If
245114237Snjl   * any of these things are different between the previous & current
246107325Siwasaki   * datagram, we send the current datagram `uncompressed'.
247107325Siwasaki   */
248107325Siwasaki  oth = (struct tcphdr *) & ((int *) &cs->cs_ip)[hlen];
249107325Siwasaki  deltaS = hlen;
250107325Siwasaki  hlen += th->th_off;
251107325Siwasaki  hlen <<= 2;
252114237Snjl  if (hlen > m->m_len)
253107325Siwasaki    return (TYPE_IP);
254107325Siwasaki
255107325Siwasaki  if (((u_short *) ip)[0] != ((u_short *) & cs->cs_ip)[0] ||
256107325Siwasaki      ((u_short *) ip)[3] != ((u_short *) & cs->cs_ip)[3] ||
257107325Siwasaki      ((u_short *) ip)[4] != ((u_short *) & cs->cs_ip)[4] ||
258107325Siwasaki      THOFFSET(th) != THOFFSET(oth) ||
259107325Siwasaki      (deltaS > 5 &&
260107325Siwasaki       memcmp(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
261107325Siwasaki      (THOFFSET(th) > 5 &&
262107325Siwasaki       memcmp(th + 1, oth + 1, (THOFFSET(th) - 5) << 2))) {
263107325Siwasaki    goto uncompressed;
264107325Siwasaki  }
265107325Siwasaki
266107325Siwasaki  /*
267107325Siwasaki   * Figure out which of the changing fields changed.  The receiver expects
268107325Siwasaki   * changes in the order: urgent, window, ack, seq (the order minimizes the
269107325Siwasaki   * number of temporaries needed in this section of code).
270107325Siwasaki   */
271107325Siwasaki  if (th->th_flags & TH_URG) {
272107325Siwasaki    deltaS = ntohs(th->th_urp);
273107325Siwasaki    ENCODEZ(deltaS);
274107325Siwasaki    changes |= NEW_U;
275107325Siwasaki  } else if (th->th_urp != oth->th_urp) {
276107325Siwasaki
277107325Siwasaki    /*
278107325Siwasaki     * argh! URG not set but urp changed -- a sensible implementation should
279107325Siwasaki     * never do this but RFC793 doesn't prohibit the change so we have to
280107325Siwasaki     * deal with it.
281107325Siwasaki     */
282107325Siwasaki    goto uncompressed;
283107325Siwasaki  }
284107325Siwasaki  deltaS = (u_short) (ntohs(th->th_win) - ntohs(oth->th_win));
285107325Siwasaki  if (deltaS) {
286107325Siwasaki    ENCODE(deltaS);
287107325Siwasaki    changes |= NEW_W;
288107325Siwasaki  }
289107325Siwasaki  deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack);
290107325Siwasaki  if (deltaA) {
291107325Siwasaki    if (deltaA > 0xffff) {
292107325Siwasaki      goto uncompressed;
293107325Siwasaki    }
294107325Siwasaki    ENCODE(deltaA);
295107325Siwasaki    changes |= NEW_A;
296107325Siwasaki  }
297107325Siwasaki  deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq);
29867754Smsmith  if (deltaS) {
29967754Smsmith    if (deltaS > 0xffff) {
30067754Smsmith      goto uncompressed;
30167754Smsmith    }
30283174Smsmith    ENCODE(deltaS);
30367754Smsmith    changes |= NEW_S;
30467754Smsmith  }
30567754Smsmith  switch (changes) {
30667754Smsmith
30787031Smsmith  case 0:
30887031Smsmith
30967754Smsmith    /*
310107325Siwasaki     * Nothing changed. If this packet contains data and the last one didn't,
311107325Siwasaki     * this is probably a data packet following an ack (normal on an
312107325Siwasaki     * interactive connection) and we send it compressed.  Otherwise it's
313107325Siwasaki     * probably a retransmit, retransmitted ack or window probe.  Send it
31487031Smsmith     * uncompressed in case the other side missed the compressed version.
31567754Smsmith     */
31667754Smsmith    if (ip->ip_len != cs->cs_ip.ip_len &&
31767754Smsmith	ntohs(cs->cs_ip.ip_len) == hlen)
31867754Smsmith      break;
31967754Smsmith
32067754Smsmith    /* (fall through) */
32183174Smsmith
32291116Smsmith  case SPECIAL_I:
32367754Smsmith  case SPECIAL_D:
324117521Snjl
32567754Smsmith    /*
326107325Siwasaki     * actual changes match one of our special case encodings -- send packet
32767754Smsmith     * uncompressed.
328107325Siwasaki     */
329107325Siwasaki    goto uncompressed;
33067754Smsmith
331107325Siwasaki  case NEW_S | NEW_A:
33291116Smsmith    if (deltaS == deltaA &&
33367754Smsmith	deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
33467754Smsmith      /* special case for echoed terminal traffic */
33567754Smsmith      changes = SPECIAL_I;
33667754Smsmith      cp = new_seq;
33767754Smsmith    }
33867754Smsmith    break;
33967754Smsmith
34067754Smsmith  case NEW_S:
34167754Smsmith    if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
34267754Smsmith      /* special case for data xfer */
34367754Smsmith      changes = SPECIAL_D;
34467754Smsmith      cp = new_seq;
34587031Smsmith    }
34667754Smsmith    break;
34767754Smsmith  }
34867754Smsmith
34967754Smsmith  deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
35067754Smsmith  if (deltaS != 1) {
351107325Siwasaki    ENCODEZ(deltaS);
352107325Siwasaki    changes |= NEW_I;
35367754Smsmith  }
35467754Smsmith  if (th->th_flags & TH_PUSH)
35567754Smsmith    changes |= TCP_PUSH_BIT;
356107325Siwasaki
357107325Siwasaki  /*
358129684Snjl   * Grab the cksum before we overwrite it below.  Then update our state with
359107325Siwasaki   * this packet's header.
360107325Siwasaki   */
361107325Siwasaki  deltaA = ntohs(th->th_sum);
362123315Snjl  memcpy(&cs->cs_ip, ip, hlen);
363107325Siwasaki
364107325Siwasaki  /*
365107325Siwasaki   * We want to use the original packet as our compressed packet. (cp -
366107325Siwasaki   * new_seq) is the number of bytes we need for compressed sequence numbers.
367107325Siwasaki   * In addition we need one byte for the change mask, one for the connection
368107325Siwasaki   * id and two for the tcp checksum. So, (cp - new_seq) + 4 bytes of header
369107325Siwasaki   * are needed.  hlen is how many bytes of the original packet to toss so
370107325Siwasaki   * subtract the two to get the new packet size.
371107325Siwasaki   */
372107325Siwasaki  deltaS = cp - new_seq;
373107325Siwasaki  cp = (u_char *) ip;
374107325Siwasaki
375107325Siwasaki  /*
376107325Siwasaki   * Since fastq traffic can jump ahead of the background traffic, we don't
377107325Siwasaki   * know what order packets will go on the line.  In this case, we always
378107325Siwasaki   * send a "new" connection id so the receiver state stays synchronized.
379107325Siwasaki   */
380107325Siwasaki  if (comp->last_xmit == cs->cs_id && compress_cid) {
381107325Siwasaki    hlen -= deltaS + 3;
382107325Siwasaki    cp += hlen;
383107325Siwasaki    *cp++ = changes;
384107325Siwasaki  } else {
385107325Siwasaki    comp->last_xmit = cs->cs_id;
386107325Siwasaki    hlen -= deltaS + 4;
387107325Siwasaki    cp += hlen;
388107325Siwasaki    *cp++ = changes | NEW_C;
389107325Siwasaki    *cp++ = cs->cs_id;
390107325Siwasaki  }
391114237Snjl  m->m_len -= hlen;
392107325Siwasaki  m->m_offset += hlen;
393107325Siwasaki  *cp++ = deltaA >> 8;
394107325Siwasaki  *cp++ = deltaA;
395107325Siwasaki  memcpy(cp, new_seq, deltaS);
396107325Siwasaki  slstat->sls_compressed++;
397107325Siwasaki  return (TYPE_COMPRESSED_TCP);
398107325Siwasaki
399107325Siwasaki  /*
400107325Siwasaki   * Update connection state cs & send uncompressed packet ('uncompressed'
401107325Siwasaki   * means a regular ip/tcp packet but with the 'conversation id' we hope to
402107325Siwasaki   * use on future compressed packets in the protocol field).
403107325Siwasaki   */
404107325Siwasakiuncompressed:
405107325Siwasaki  memcpy(&cs->cs_ip, ip, hlen);
406107325Siwasaki  ip->ip_p = cs->cs_id;
407107325Siwasaki  comp->last_xmit = cs->cs_id;
408107325Siwasaki  return (TYPE_UNCOMPRESSED_TCP);
409107325Siwasaki}
410107325Siwasaki
41167754Smsmith
41267754Smsmithint
41367754Smsmithsl_uncompress_tcp(u_char ** bufp, int len, u_int type, struct slcompress *comp,
41467754Smsmith                  struct slstat *slstat, int max_state)
41567754Smsmith{
41667754Smsmith  register u_char *cp;
41767754Smsmith  register u_int hlen, changes;
41867754Smsmith  register struct tcphdr *th;
41967754Smsmith  register struct cstate *cs;
42067754Smsmith  register struct ip *ip;
421107325Siwasaki  u_short *bp;
422107325Siwasaki
423107325Siwasaki  switch (type) {
42467754Smsmith
42567754Smsmith  case TYPE_UNCOMPRESSED_TCP:
42667754Smsmith    ip = (struct ip *) * bufp;
42767754Smsmith    if (ip->ip_p > max_state)
428107325Siwasaki      goto bad;
429107325Siwasaki    cs = &comp->rstate[comp->last_recv = ip->ip_p];
43067754Smsmith    comp->flags &= ~SLF_TOSS;
431129684Snjl    ip->ip_p = IPPROTO_TCP;
432127175Snjl
433127175Snjl    /*
434123315Snjl     * Calculate the size of the TCP/IP header and make sure that we don't
435127175Snjl     * overflow the space we have available for it.
43667754Smsmith     */
43767754Smsmith    hlen = ip->ip_hl << 2;
43867754Smsmith    if (hlen + sizeof(struct tcphdr) > len)
43967754Smsmith      goto bad;
44067754Smsmith    th = (struct tcphdr *) & ((char *) ip)[hlen];
44191116Smsmith    hlen += THOFFSET(th) << 2;
44267754Smsmith    if (hlen > MAX_HDR)
44367754Smsmith      goto bad;
44467754Smsmith    memcpy(&cs->cs_ip, ip, hlen);
44567754Smsmith    cs->cs_hlen = hlen;
44667754Smsmith    slstat->sls_uncompressedin++;
44767754Smsmith    return (len);
44867754Smsmith
44967754Smsmith  default:
45067754Smsmith    goto bad;
45167754Smsmith
45267754Smsmith  case TYPE_COMPRESSED_TCP:
45367754Smsmith    break;
45467754Smsmith  }
45567754Smsmith
45667754Smsmith  /* We've got a compressed packet. */
45767754Smsmith  slstat->sls_compressedin++;
45891116Smsmith  cp = *bufp;
45991116Smsmith  changes = *cp++;
46067754Smsmith  log_Printf(LogDEBUG, "compressed: changes = %02x\n", changes);
46167754Smsmith
46267754Smsmith  if (changes & NEW_C) {
46367754Smsmith    /*
46467754Smsmith     * Make sure the state index is in range, then grab the state. If we have
46567754Smsmith     * a good state index, clear the 'discard' flag.
46667754Smsmith     */
46767754Smsmith    if (*cp > max_state || comp->last_recv == 255)
46867754Smsmith      goto bad;
469115351Snjl
47067754Smsmith    comp->flags &= ~SLF_TOSS;
47167754Smsmith    comp->last_recv = *cp++;
47267754Smsmith  } else {
47391116Smsmith    /*
47467754Smsmith     * this packet has an implicit state index.  If we've had a line error
47567754Smsmith     * since the last time we got an explicit state index, we have to toss
47667754Smsmith     * the packet.
47767754Smsmith     */
47867754Smsmith    if (comp->flags & SLF_TOSS) {
47967754Smsmith      slstat->sls_tossed++;
48067754Smsmith      return (0);
48167754Smsmith    }
48267754Smsmith  }
48367754Smsmith  cs = &comp->rstate[comp->last_recv];
48467754Smsmith  hlen = cs->cs_ip.ip_hl << 2;
48567754Smsmith  th = (struct tcphdr *) & ((u_char *) & cs->cs_ip)[hlen];
48667754Smsmith  th->th_sum = htons((*cp << 8) | cp[1]);
48767754Smsmith  cp += 2;
48867754Smsmith  if (changes & TCP_PUSH_BIT)
48967754Smsmith    th->th_flags |= TH_PUSH;
49067754Smsmith  else
49167754Smsmith    th->th_flags &= ~TH_PUSH;
49267754Smsmith
49367754Smsmith  switch (changes & SPECIALS_MASK) {
49467754Smsmith  case SPECIAL_I:
49567754Smsmith    {
49667754Smsmith      register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
49767754Smsmith
49867754Smsmith      th->th_ack = htonl(ntohl(th->th_ack) + i);
49967754Smsmith      th->th_seq = htonl(ntohl(th->th_seq) + i);
50067754Smsmith    }
50167754Smsmith    break;
50267754Smsmith
50385756Smsmith  case SPECIAL_D:
50467754Smsmith    th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
50567754Smsmith		       - cs->cs_hlen);
50667754Smsmith    break;
50767754Smsmith
50867754Smsmith  default:
50982367Smsmith    if (changes & NEW_U) {
51067754Smsmith      th->th_flags |= TH_URG;
51199146Siwasaki      DECODEU(th->th_urp)
51267754Smsmith    } else
51367754Smsmith      th->th_flags &= ~TH_URG;
51467754Smsmith    if (changes & NEW_W)
51585756Smsmith      DECODES(th->th_win)
51667754Smsmith	if (changes & NEW_A)
51785756Smsmith	DECODEL(th->th_ack)
518115351Snjl	  if (changes & NEW_S) {
519115351Snjl	  log_Printf(LogDEBUG, "NEW_S: %02x, %02x, %02x\n",
520115351Snjl		    *cp, cp[1], cp[2]);
521115351Snjl	  DECODEL(th->th_seq)
522115351Snjl	}
523115351Snjl    break;
524115351Snjl  }
525115351Snjl  if (changes & NEW_I) {
526115351Snjl    DECODES(cs->cs_ip.ip_id)
527115351Snjl  } else
528115351Snjl    cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
529115351Snjl
530115351Snjl  log_Printf(LogDEBUG, "Uncompress: id = %04x, seq = %08lx\n",
531115351Snjl	    cs->cs_ip.ip_id, (u_long)ntohl(th->th_seq));
532115351Snjl
533115351Snjl  /*
534115351Snjl   * At this point, cp points to the first byte of data in the packet.
535115351Snjl   * Back up cp by the tcp/ip header length to make room for the
536115351Snjl   * reconstructed header (we assume the packet we were handed has enough
537115351Snjl   * space to prepend 128 bytes of header).  Adjust the length to account
538115351Snjl   * for the new header & fill in the IP total length.
53980062Smsmith   */
54067754Smsmith  len -= (cp - *bufp);
54167754Smsmith  if (len < 0)
54267754Smsmith    /*
54367754Smsmith     * we must have dropped some characters (crc should detect this but the
54467754Smsmith     * old slip framing won't)
54567754Smsmith     */
54667754Smsmith    goto bad;
54767754Smsmith
54867754Smsmith  *bufp = cp - cs->cs_hlen;
54967754Smsmith  len += cs->cs_hlen;
55067754Smsmith  cs->cs_ip.ip_len = htons(len);
55167754Smsmith
55267754Smsmith  /* recompute the ip header checksum */
55367754Smsmith  cs->cs_ip.ip_sum = 0;
55467754Smsmith  bp = (u_short *)&cs->cs_ip;
55567754Smsmith  for (changes = 0; hlen > 0; hlen -= 2)
55667754Smsmith    changes += *bp++;
55767754Smsmith  changes = (changes & 0xffff) + (changes >> 16);
55867754Smsmith  changes = (changes & 0xffff) + (changes >> 16);
55967754Smsmith  cs->cs_ip.ip_sum = ~changes;
56083174Smsmith
56167754Smsmith  /* And copy the result into our buffer */
56267754Smsmith  memcpy(*bufp, &cs->cs_ip, cs->cs_hlen);
56367754Smsmith
56467754Smsmith  return (len);
56591116Smsmithbad:
56667754Smsmith  comp->flags |= SLF_TOSS;
56767754Smsmith  slstat->sls_errorin++;
56867754Smsmith  return (0);
56999679Siwasaki}
57067754Smsmith
57167754Smsmithint
57267754Smsmithsl_Show(struct cmdargs const *arg)
57384491Smsmith{
57484491Smsmith  prompt_Printf(arg->prompt, "VJ compression statistics:\n");
57567754Smsmith  prompt_Printf(arg->prompt, "  Out:  %d (compress) / %d (total)",
57667754Smsmith	        arg->bundle->ncp.ipcp.vj.slstat.sls_compressed,
57791116Smsmith                arg->bundle->ncp.ipcp.vj.slstat.sls_packets);
57867754Smsmith  prompt_Printf(arg->prompt, "  %d (miss) / %d (search)\n",
57967754Smsmith	        arg->bundle->ncp.ipcp.vj.slstat.sls_misses,
58067754Smsmith                arg->bundle->ncp.ipcp.vj.slstat.sls_searches);
58167754Smsmith  prompt_Printf(arg->prompt, "  In:  %d (compress), %d (uncompress)",
58299679Siwasaki	        arg->bundle->ncp.ipcp.vj.slstat.sls_compressedin,
58367754Smsmith                arg->bundle->ncp.ipcp.vj.slstat.sls_uncompressedin);
58467754Smsmith  prompt_Printf(arg->prompt, "  %d (error),  %d (tossed)\n",
58567754Smsmith	        arg->bundle->ncp.ipcp.vj.slstat.sls_errorin,
58667754Smsmith                arg->bundle->ncp.ipcp.vj.slstat.sls_tossed);
58767754Smsmith  return 0;
58867754Smsmith}
58967754Smsmith