home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / internet / tcpipsrc / Drivers / c / sl_compres < prev    next >
Encoding:
Text File  |  1995-02-20  |  28.0 KB  |  793 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #include "global.h"
  6. #include "timer.h"
  7. #include "ip.h"
  8.  
  9. #include "bbc.h"
  10. #include "terminal.h"
  11.  
  12. #include "sl_compres.h"
  13.  
  14. #define BCOPY(src, dst, amt) memcpy(dst, src, amt)
  15. #define OVBCOPY(src, dst, amt) memmove(dst, src, amt)
  16. #define BCMP(src, dst, amt) memcmp(dst, src, amt)
  17. #define bzero(dst, amt) memset(dst, 0, amt);
  18. #define mtod(m, t) ((t)(m->data))
  19.  
  20. typedef    u_long    tcp_seq;
  21. #define IPPROTO_TCP             6        /* tcp */
  22. /*
  23.  * TCP header.
  24.  * Per RFC 793, September, 1981.
  25.  */
  26.  
  27. struct net_tcphdr {
  28.     u_short    th_sport;        /* source port */
  29.     u_short    th_dport;        /* destination port */
  30.     tcp_seq    th_seq;            /* sequence number */
  31.     tcp_seq    th_ack;            /* acknowledgement number */
  32.     u_int    th_x2:4;        /* (unused) */
  33.     u_int    th_off:4;        /* data offset */
  34.     u_int    th_flags:8;
  35. #define    TH_FIN    0x01
  36. #define    TH_SYN    0x02
  37. #define    TH_RST    0x04
  38. #define    TH_PUSH    0x08
  39. #define    TH_ACK    0x10
  40. #define    TH_URG    0x20
  41.     u_int    th_win:16;        /* window */
  42.     u_short    th_sum;            /* checksum */
  43.     u_short    th_urp;            /* urgent pointer */
  44. };
  45.  
  46.  
  47. static u_short ntohs(u_short n)
  48. {
  49.   return ((n & 0xff) << 8) |
  50.          ((n >> 8) & 0xff);
  51. }
  52.  
  53. static u_long ntohl(u_long n)
  54. {
  55.   return ((n & 0xff) << 24) |
  56.          ((n & 0xff00) << 8) |
  57.          ((n & 0xff0000) >> 8) |
  58.          ((n & 0xff000000) >> 24);
  59. }
  60.  
  61. /*
  62. #define ntohl(a) \
  63.  ((a >> 24) | \
  64.   ((a & 0xff0000) >> 8) | \
  65.   ((a & 0xff00) << 8) | \
  66.   (a << 24) )
  67. */
  68. #define htonl ntohl
  69. /*
  70. #define ntohs(a) \
  71.  ((( a & 0xff00) >> 8) | \
  72.   (( a & 0xff) << 8) )
  73. */  
  74. #define htons ntohs
  75.  
  76.  
  77. /*
  78.  * See "sl_compress.h" for additional info
  79.  */
  80.     
  81. /*
  82.  * The following macros are used to encode and decode numbers.  They all
  83.  * assume that `cp' points to a buffer where the next byte encoded (decoded)
  84.  * is to be stored (retrieved).  Since the decode routines do arithmetic,
  85.  * they have to convert from and to network byte order.
  86.  */
  87.  
  88. /*
  89.  * ENCODE encodes a number that is known to be non-zero.  ENCODEZ checks for
  90.  * zero (zero has to be encoded in the long, 3 byte form).
  91.  */
  92. #define ENCODE(n) { \
  93.      if ((u_short)(n) >= 256) { \
  94.           *cp++ = 0; \
  95.           cp[1] = (n); \
  96.           cp[0] = (n) >> 8; \
  97.           cp += 2; \
  98.      } else { \
  99.           *cp++ = (n); \
  100.      } \
  101. }
  102. #define ENCODEZ(n) { \
  103.      if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
  104.           *cp++ = 0; \
  105.           cp[1] = (n); \
  106.           cp[0] = (n) >> 8; \
  107.           cp += 2; \
  108.      } else { \
  109.           *cp++ = (n); \
  110.      } \
  111. }
  112.  
  113. /*
  114.  * DECODEL takes the (compressed) change at byte cp and adds it to the
  115.  * current value of packet field 'f' (which must be a 4-byte (long) integer
  116.  * in network byte order).  DECODES does the same for a 2-byte (short) field.
  117.  * DECODEU takes the change at cp and stuffs it into the (short) field f.
  118.  * 'cp' is updated to point to the next field in the compressed header.
  119.  */
  120. #define DECODEL(f) { \
  121.      if (*cp == 0) {\
  122.           (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
  123.           cp += 3; \
  124.      } else { \
  125.           (f) = htonl(ntohl(f) + (u_long)*cp++); \
  126.      } \
  127. }
  128. #define DECODES(f) { \
  129.      if (*cp == 0) {\
  130.           (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
  131.           cp += 3; \
  132.      } else { \
  133.           (f) = htons(ntohs(f) + (u_long)*cp++); \
  134.      } \
  135. }
  136. #define DECODEU(f) { \
  137.      if (*cp == 0) {\
  138.           (f) = htons((cp[1] << 8) | cp[2]); \
  139.           cp += 3; \
  140.      } else { \
  141.           (f) = htons((u_long)*cp++); \
  142.      } \
  143. }
  144.  
  145. /*
  146.    A.2  Compression
  147.  
  148.    This routine looks daunting but isn't really.  The code splits into four
  149.    approximately equal sized sections:  The first quarter manages a
  150.    circularly linked, least-recently-used list of `active' TCP
  151.    connections./47/  The second figures out the sequence/ack/window/urg
  152.    changes and builds the bulk of the compressed packet.  The third handles
  153.    the special-case encodings.  The last quarter does packet ID and
  154.    connection ID encoding and replaces the original packet header with the
  155.    compressed header.
  156.  
  157.    The arguments to this routine are a pointer to a packet to be
  158.    compressed, a pointer to the compression state data for the serial line,
  159.    and a flag which enables or disables connection id (C bit) compression.
  160.  
  161.    Compression is done `in-place' so, if a compressed packet is created,
  162.    both the start address and length of the incoming packet (the off and
  163.    len fields of m) will be updated to reflect the removal of the original
  164.    header and its replacement by the compressed header.  If either a
  165.    compressed or uncompressed packet is created, the compression state is
  166.    updated.  This routines returns the packet type for the transmit framer
  167.    (TYPE_IP, TYPE_UNCOMPRESSED_TCP or TYPE_COMPRESSED_TCP).
  168.  
  169.    Because 16 and 32 bit arithmetic is done on various header fields, the
  170.    incoming IP packet must be aligned appropriately (e.g., on a SPARC, the
  171.    IP header is aligned on a 32-bit boundary).  Substantial changes would
  172.    have to be made to the code below if this were not true (and it would
  173.    probably be cheaper to byte copy the incoming header to somewhere
  174.    correctly aligned than to make those changes).
  175.  
  176.    Note that the outgoing packet will be aligned arbitrarily (e.g., it
  177.    could easily start on an odd-byte boundary).
  178. */
  179.    u_char
  180.    sl_compress_tcp(char **bufp, int *len, struct slcompress *comp, int compress_cid)
  181.    {
  182.         register struct cstate *cs = comp->last_cs->cs_next;
  183.         register struct net_ip *ip = (struct net_ip *)*bufp;
  184.         register u_int hlen = ip->ip_hl;
  185.         register struct net_tcphdr *oth;       /* last TCP header */
  186.         register struct net_tcphdr *th;        /* current TCP header */
  187.  
  188.  
  189.  
  190. /*
  191.    ----------------------------
  192.     47. The two most common operations on the connection list are a `find'
  193.    that terminates at the first entry (a new packet for the most recently
  194.    used connection) and moving the last entry on the list to the head of
  195.    the list (the first packet from a new connection).  A circular list
  196.    efficiently handles these two operations.
  197.  
  198. */
  199.  
  200.         register u_int deltaS, deltaA;     /* general purpose temporaries */
  201.         register u_int changes = 0;        /* change mask */
  202.         u_char new_seq[16];                /* changes from last to current */
  203.         register u_char *cp = new_seq;
  204.  
  205.         /*
  206.          * Bail if this is an IP fragment or if the TCP packet isn't
  207.          * `compressible' (i.e., ACK isn't set or some other control bit is
  208.          * set).  (We assume that the caller has already made sure the packet
  209.          * is IP proto TCP).
  210.          */
  211.         if ((ip->ip_off & htons(0x3fff)) || *len < 40)
  212.              return (TYPE_IP);
  213.  
  214.         th = (struct net_tcphdr *) & ((int *) ip)[hlen];
  215.         if ((th->th_flags & (TH_SYN | TH_FIN | TH_RST | TH_ACK)) != TH_ACK)
  216.              return (TYPE_IP);
  217.  
  218.         /*
  219.          * Packet is compressible -- we're going to send either a
  220.          * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need to
  221.          * locate (or create) the connection state.  Special case the most
  222.          * recently used connection since it's most likely to be used again &
  223.          * we don't have to do any reordering if it's used.
  224.          */
  225.         if (ip->ip_src != cs->cs_ip.ip_src ||
  226.             ip->ip_dst != cs->cs_ip.ip_dst ||
  227.             *(int *) th != ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl]) {
  228.  
  229.              /*
  230.               * Wasn't the first -- search for it.
  231.               *
  232.               * States are kept in a circularly linked list with last_cs
  233.               * pointing to the end of the list.  The list is kept in lru
  234.               * order by moving a state to the head of the list whenever
  235.               * it is referenced.  Since the list is short and,
  236.               * empirically, the connection we want is almost always near
  237.               * the front, we locate states via linear search.  If we
  238.               * don't find a state for the datagram, the oldest state is
  239.               * (re-)used.
  240.               */
  241.              register struct cstate *lcs;
  242.              register struct cstate *lastcs = comp->last_cs;
  243.  
  244.              do {
  245.                   lcs = cs;
  246.                   cs = cs->cs_next;
  247.                   if (ip->ip_src == cs->cs_ip.ip_src
  248.                       && ip->ip_dst == cs->cs_ip.ip_dst
  249.                       && *(int *) th == ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl])
  250.                        goto found;
  251.              } while (cs != lastcs);
  252.  
  253.              /*
  254.               * Didn't find it -- re-use oldest cstate.  Send an
  255.               * uncompressed packet that tells the other side what
  256.               * connection number we're using for this conversation. Note
  257.               * that since the state list is circular, the oldest state
  258.               * points to the newest and we only need to set last_cs to
  259.               * update the lru linkage.
  260.               */
  261.              comp->last_cs = lcs;
  262.              hlen += th->th_off;
  263.              hlen <<= 2;
  264.              goto uncompressed;
  265.  
  266.    found:
  267.              /* Found it -- move to the front on the connection list. */
  268.              if (lastcs == cs)
  269.                   comp->last_cs = lcs;
  270.              else {
  271.                   lcs->cs_next = cs->cs_next;
  272.                   cs->cs_next = lastcs->cs_next;
  273.                   lastcs->cs_next = cs;
  274.              }
  275.         }
  276.         /*
  277.          * Make sure that only what we expect to change changed. The first
  278.          * line of the `if' checks the IP protocol version, header length &
  279.          * type of service.  The 2nd line checks the "Don't fragment" bit.
  280.          * The 3rd line checks the time-to-live and protocol (the protocol
  281.          * check is unnecessary but costless).  The 4th line checks the TCP
  282.          * header length.  The 5th line checks IP options, if any.  The 6th
  283.          * line checks TCP options, if any.  If any of these things are
  284.          * different between the previous & current datagram, we send the
  285.          * current datagram `uncompressed'.
  286.          */
  287.         oth = (struct net_tcphdr *) & ((int *) &cs->cs_ip)[hlen];
  288.         deltaS = hlen;
  289.         hlen += th->th_off;
  290.         hlen <<= 2;
  291.  
  292.         if (((u_short *) ip)[0] != ((u_short *) &cs->cs_ip)[0] ||
  293.             ((u_short *) ip)[3] != ((u_short *) &cs->cs_ip)[3] ||
  294.             ((u_short *) ip)[4] != ((u_short *) &cs->cs_ip)[4] ||
  295.             th->th_off != oth->th_off ||
  296.             (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
  297.             (th->th_off > 5 && BCMP(th + 1, oth + 1, (th->th_off - 5) << 2)))
  298.              goto uncompressed;
  299.  
  300.         /*
  301.          * Figure out which of the changing fields changed.  The receiver
  302.          * expects changes in the order: urgent, window, ack, seq.
  303.          */
  304.         if (th->th_flags & TH_URG) {
  305.              deltaS = ntohs(th->th_urp);
  306.              ENCODEZ(deltaS);
  307.              changes |= NEW_U;
  308.         } else if (th->th_urp != oth->th_urp)
  309.              /*
  310.               * argh! URG not set but urp changed -- a sensible
  311.               * implementation should never do this but RFC793 doesn't
  312.               * prohibit the change so we have to deal with it.
  313.               */
  314.              goto uncompressed;
  315.  
  316.         if (deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win)), deltaS!=0) {
  317.              ENCODE(deltaS);
  318.              changes |= NEW_W;
  319.         }
  320.         if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack), deltaA!=0) {
  321.              if (deltaA > 0xffff)
  322.                   goto uncompressed;
  323. /*
  324.   twprintf(">< %.8x + %d", ntohl(oth->th_ack), deltaA);
  325.   twprintf(" = %.8x\r\n", ntohl(th->th_ack));
  326. */
  327.              ENCODE(deltaA);
  328.              changes |= NEW_A;
  329.         }
  330.         if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq), deltaS!=0) {
  331.              if (deltaS > 0xffff)
  332.                   goto uncompressed;
  333.              ENCODE(deltaS);
  334.              changes |= NEW_S;
  335.         }
  336.         /*
  337.          * Look for the special-case encodings.
  338.          */
  339.         switch (changes) {
  340.  
  341.         case 0:
  342.              /*
  343.               * Nothing changed. If this packet contains data and the last
  344.               * one didn't, this is probably a data packet following an
  345.               * ack (normal on an interactive connection) and we send it
  346.               * compressed.  Otherwise it's probably a retransmit,
  347.               * retransmitted ack or window probe.  Send it uncompressed
  348.               * in case the other side missed the compressed version.
  349.               */
  350.              if (ip->ip_len != cs->cs_ip.ip_len &&
  351.                  ntohs(cs->cs_ip.ip_len) == hlen)
  352.                   break;
  353.  
  354.              /* (fall through) */
  355.  
  356.         case SPECIAL_I:
  357.         case SPECIAL_D:
  358.              /*
  359.               * Actual changes match one of our special case encodings --
  360.               * send packet uncompressed.
  361.               */
  362.              goto uncompressed;
  363.  
  364.         case NEW_S | NEW_A:
  365.              if (deltaS == deltaA &&
  366.                  deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
  367.                   /* special case for echoed terminal traffic */
  368.                   changes = SPECIAL_I;
  369.                   cp = new_seq;
  370.              }
  371.              break;
  372.  
  373.         case NEW_S:
  374.              if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
  375.                   /* special case for data xfer */
  376.                   changes = SPECIAL_D;
  377.                   cp = new_seq;
  378.              }
  379.              break;
  380.         }
  381.         deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
  382.         if (deltaS != 1) {
  383.              ENCODEZ(deltaS);
  384.              changes |= NEW_I;
  385.         }
  386.         if (th->th_flags & TH_PUSH)
  387.              changes |= TCP_PUSH_BIT;
  388.         /*
  389.          * Grab the cksum before we overwrite it below.  Then update our
  390.          * state with this packet's header.
  391.          */
  392.         deltaA = ntohs(th->th_sum);
  393.         BCOPY(ip, &cs->cs_ip, hlen);
  394.  
  395.         /*
  396.          * We want to use the original packet as our compressed packet. (cp -
  397.          * new_seq) is the number of bytes we need for compressed sequence
  398.          * numbers.  In addition we need one byte for the change mask, one
  399.          * for the connection id and two for the tcp checksum. So, (cp -
  400.          * new_seq) + 4 bytes of header are needed.  hlen is how many bytes
  401.          * of the original packet to toss so subtract the two to get the new
  402.          * packet size.
  403.          */
  404.         deltaS = cp - new_seq;
  405.         cp = (u_char *) ip;
  406.         if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
  407.              comp->last_xmit = cs->cs_id;
  408.              hlen -= deltaS + 4;
  409.              cp += hlen;
  410.              *cp++ = changes | NEW_C;
  411.              *cp++ = cs->cs_id;
  412.         } else {
  413.              hlen -= deltaS + 3;
  414.              cp += hlen;
  415.              *cp++ = changes;
  416.         }
  417.         *len -= hlen;
  418.         *bufp += hlen;
  419.         *cp++ = deltaA >> 8;
  420.         *cp++ = deltaA;
  421.  
  422.         BCOPY(new_seq, cp, deltaS);
  423.         return (TYPE_COMPRESSED_TCP);
  424.  
  425.    uncompressed:
  426.         /*
  427.          * Update connection state cs & send uncompressed packet
  428.          * ('uncompressed' means a regular ip/tcp packet but with the
  429.          * 'conversation id' we hope to use on future compressed packets in
  430.          * the protocol field).
  431.          */
  432.         BCOPY(ip, &cs->cs_ip, hlen);
  433.         ip->ip_p = cs->cs_id;
  434.         comp->last_xmit = cs->cs_id;
  435.         return (TYPE_UNCOMPRESSED_TCP);
  436.    }
  437.  
  438.  
  439. /*
  440.    A.3  Decompression
  441.  
  442.    This routine decompresses a received packet.  It is called with a
  443.    pointer to the packet, the packet length and type, and a pointer to the
  444.    compression state structure for the incoming serial line.  It returns a
  445.    pointer to the resulting packet or zero if there were errors in the
  446.    incoming packet.  If the packet is COMPRESSED_TCP or UNCOMPRESSED_TCP,
  447.    the compression state will be updated.
  448.  
  449.    The new packet will be constructed in-place.  That means that there must
  450.    be 128 bytes of free space in front of bufp to allow room for the
  451.    reconstructed IP and TCP headers.  The reconstructed packet will be
  452.    aligned on a 32-bit boundary.
  453. */
  454.   u_char *
  455.    sl_uncompress_tcp(char *bufp, int *len, u_int type, struct slcompress *comp)
  456.    {
  457.         register u_char *cp;
  458.         register u_int hlen, changes;
  459.         register struct net_tcphdr *th;
  460.         register struct cstate *cs;
  461.         register struct net_ip *ip;
  462.  
  463.         switch (type) {
  464.  
  465.         case TYPE_ERROR:
  466.         default:
  467.              goto bad;
  468.  
  469.         case TYPE_IP:
  470.              return (bufp);
  471.  
  472.         case TYPE_UNCOMPRESSED_TCP:
  473.              /*
  474.               * Locate the saved state for this connection.  If the state
  475.               * index is legal, clear the 'discard' flag.
  476.               */
  477.              ip = (struct net_ip *) bufp;
  478.              if (ip->ip_p >= MAX_STATES)
  479.                   goto bad;
  480.  
  481.              cs = &comp->rstate[comp->last_recv = ip->ip_p];
  482.              comp->flags &= ~SLF_TOSS;
  483.              /*
  484.               * Restore the IP protocol field then save a copy of this
  485.               * packet header.  (The checksum is zeroed in the copy so we
  486.               * don't have to zero it each time we process a compressed
  487.               * packet.
  488.               */
  489.              ip->ip_p = IPPROTO_TCP;
  490.              hlen = ip->ip_hl;
  491.              hlen += ((struct net_tcphdr *) & ((int *) ip)[hlen])->th_off;
  492.              hlen <<= 2;
  493.              BCOPY(ip, &cs->cs_ip, hlen);
  494.              cs->cs_ip.ip_sum = 0;
  495.              cs->cs_hlen = hlen;
  496.              return (bufp);
  497.  
  498.         case TYPE_COMPRESSED_TCP:
  499.              break;
  500.         }
  501.         /* We've got a compressed packet. */
  502.         cp = bufp;
  503.         changes = *cp++;
  504.         if (changes & NEW_C) {
  505.              /*
  506.               * Make sure the state index is in range, then grab the
  507.               * state. If we have a good state index, clear the 'discard'
  508.               * flag.
  509.               */
  510.              if (*cp >= MAX_STATES)
  511.                   goto bad;
  512.  
  513.              comp->flags &= ~SLF_TOSS;
  514.              comp->last_recv = *cp++;
  515.         } else {
  516.              /*
  517.               * This packet has an implicit state index.  If we've had a
  518.               * line error since the last time we got an explicit state
  519.               * index, we have to toss the packet.
  520.               */
  521.              if (comp->flags & SLF_TOSS)
  522.                   return ((u_char *) 0);
  523.         }
  524.         /*
  525.          * Find the state then fill in the TCP checksum and PUSH bit.
  526.          */
  527.         cs = &comp->rstate[comp->last_recv];
  528.         hlen = cs->cs_ip.ip_hl << 2;
  529.         th = (struct net_tcphdr *) & ((u_char *) &cs->cs_ip)[hlen];
  530.         th->th_sum = htons( ((*cp & 0xff)<<8) | (cp[1]&0xff) );
  531.         cp += 2;
  532.         if (changes & TCP_PUSH_BIT)
  533.              th->th_flags |= TH_PUSH;
  534.         else
  535.              th->th_flags &= ~TH_PUSH;
  536.  
  537.         /*
  538.          * Fix up the state's ack, seq, urg and win fields based on the
  539.          * changemask.
  540.          */
  541.         switch (changes & SPECIALS_MASK) {
  542.         case SPECIAL_I:
  543.              {
  544.              register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
  545.              th->th_ack = htonl(ntohl(th->th_ack) + i);
  546.              th->th_seq = htonl(ntohl(th->th_seq) + i);
  547.              }
  548.              break;
  549.  
  550.         case SPECIAL_D:
  551.              th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
  552.                           - cs->cs_hlen);
  553.              break;
  554.  
  555.         default:
  556.              if (changes & NEW_U) {
  557.                   th->th_flags |= TH_URG;
  558.                   DECODEU(th->th_urp)
  559.              } else
  560.                   th->th_flags &= ~TH_URG;
  561.              if (changes & NEW_W)
  562.                   DECODES(th->th_win)
  563.              if (changes & NEW_A)
  564. /* {
  565.   int offset;
  566.   offset = (*cp==0)?(cp[1]<<8)+cp[2]:cp[0];
  567.   twprintf("<> %.8x + %d", ntohl(th->th_ack), offset); */
  568.                   DECODEL(th->th_ack)
  569. /*  twprintf(" = %.8x\r\n", ntohl(th->th_ack));
  570. } */
  571.              if (changes & NEW_S)
  572.                   DECODEL(th->th_seq)
  573.              break;
  574.         }
  575.         /* Update the IP ID */
  576.         if (changes & NEW_I)
  577.              DECODES(cs->cs_ip.ip_id)
  578.         else
  579.              cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
  580.  
  581.         /*
  582.          * At this point, cp points to the first byte of data in the packet.
  583.          * If we're not aligned on a 4-byte boundary, copy the data down so
  584.          * the IP & TCP headers will be aligned.  Then back up cp by the
  585.          * TCP/IP header length to make room for the reconstructed header (we
  586.          * assume the packet we were handed has enough space to prepend 128
  587.          * bytes of header).  Adjust the lenth to account for the new header
  588.          * & fill in the IP total length.
  589.          */
  590.         *len -= (cp - bufp);
  591.         if (*len < 0)
  592.              /*
  593.               * we must have dropped some characters (crc should detect
  594.               * this but the old slip framing won't)
  595.               */
  596.              goto bad;
  597.  
  598.         if ((int) cp & 3) {
  599.              if (*len > 0)
  600.                   OVBCOPY(cp, (u_char *) ((int) cp & ~3), *len);
  601.              cp = (u_char *) ((int) cp & ~3);
  602.         }
  603.         cp -= cs->cs_hlen;
  604.         *len += cs->cs_hlen;
  605.         cs->cs_ip.ip_len = htons(*len);
  606.         BCOPY(&cs->cs_ip, cp, cs->cs_hlen);
  607.  
  608.         /* recompute the ip header checksum */
  609.         {
  610.              register u_short *bp = (u_short *) cp;
  611.              for (changes = 0; hlen > 0; hlen -= 2)
  612.                   changes += *bp++;
  613.              changes = (changes & 0xffff) + (changes >> 16);
  614.              changes = (changes & 0xffff) + (changes >> 16);
  615.              ((struct net_ip *)cp)->ip_sum = ~changes;
  616.         }
  617.  
  618.         return (cp);
  619.  
  620.    bad:
  621.         comp->flags |= SLF_TOSS;
  622.         return ((u_char *) 0);
  623.    }
  624.  
  625. /*
  626.    A.4  Initialization
  627.  
  628.    This routine initializes the state structure for both the transmit and
  629.    receive halves of some serial line.  It must be called each time the
  630.    line is brought up.
  631. */
  632.    int
  633.    sl_compress_init(compptr)
  634.         struct slcompress **compptr;
  635.    {
  636.         register u_int i;
  637.         struct slcompress *comp = *compptr;
  638.         register struct cstate *tstate;
  639.  
  640.         if (comp==NULL)
  641.         {
  642.           if (comp = (struct slcompress *)malloc(sizeof(struct slcompress)), comp==NULL)
  643.             return 0;
  644.         }
  645.         tstate = comp->tstate;
  646.         
  647.         /*
  648.          * Clean out any junk left from the last time line was used.
  649.          */
  650.         bzero((char *) comp, sizeof(*comp));
  651.         /*
  652.          * Link the transmit states into a circular list.
  653.          */
  654.         for (i = MAX_STATES - 1; i > 0; --i) {
  655.              tstate[i].cs_id = i;
  656.              tstate[i].cs_next = &tstate[i - 1];
  657.         }
  658.         tstate[0].cs_next = &tstate[MAX_STATES - 1];
  659.         tstate[0].cs_id = 0;
  660.         comp->last_cs = &tstate[0];
  661.         /*
  662.          * Make sure we don't accidentally do CID compression
  663.          * (assumes MAX_STATES < 255).
  664.          */
  665.         comp->last_recv = 255;
  666.         comp->last_xmit = 255;
  667.         *compptr = comp;
  668.         return 1;
  669.    }
  670. /*
  671.  
  672.    A.5  Berkeley Unix dependencies
  673.  
  674.    Note:  The following is of interest only if you are trying to bring the
  675.    sample code up on a system that is not derived from 4BSD (Berkeley
  676.    Unix).
  677.  
  678.    The code uses the normal Berkeley Unix header files (from
  679.    /usr/include/netinet) for definitions of the structure of IP and TCP
  680.    headers.  The structure tags tend to follow the protocol RFCs closely
  681.    and should be obvious even if you do not have access to a 4BSD
  682.    system./48/
  683.  
  684.    The macro BCOPY(src, dst, amt) is invoked to copy amt bytes from src to
  685.    dst.  In BSD, it translates into a call to bcopy.  If you have the
  686.    misfortune to be running System-V Unix, it can be translated into a call
  687.    to memcpy.  The macro OVBCOPY(src, dst, amt) is used to copy when src
  688.    and dst overlap (i.e., when doing the 4-byte alignment copy).  In the
  689.    BSD kernel, it translates into a call to ovbcopy.  Since AT&T botched
  690.    the definition of memcpy, this should probably translate into a copy
  691.    loop under System-V.
  692.  
  693.    The macro BCMP(src, dst, amt) is invoked to compare amt bytes of src and
  694.    dst for equality.  In BSD, it translates into a call to bcmp.  In
  695.    System-V, it can be translated into a call to memcmp or you can write a
  696.    routine to do the compare.  The routine should return zero if all bytes
  697.    of src and dst are equal and non-zero otherwise.
  698.  
  699.    The routine ntohl(dat) converts (4 byte) long dat from network byte
  700.    order to host byte order.  On a reasonable cpu this can be the no-op
  701.    macro:
  702.                            #define ntohl(dat) (dat)
  703.  
  704.    On a Vax or IBM PC (or anything with Intel byte order), you will have to
  705.    define a macro or routine to rearrange bytes.
  706.  
  707.    The routine ntohs(dat) is like ntohl but converts (2 byte) shorts
  708.    instead of longs.  The routines htonl(dat) and htons(dat) do the inverse
  709.    transform (host to network byte order) for longs and shorts.
  710.  
  711.  
  712.    B  Compatibility with past mistakes
  713.  
  714.    When combined with the modern PPP serial line protocol[9], the use of
  715.    header compression is automatic and invisible to the user.
  716.    Unfortunately, many sites have existing users of the SLIP described in
  717.    [12] which doesn't allow for different protocol types to distinguish
  718.    header compressed packets from IP packets or for version numbers or an
  719.    option exchange that could be used to automatically negotiate header
  720.    compression.
  721.  
  722.    The author has used the following tricks to allow header compressed SLIP
  723.    to interoperate with the existing servers and clients.  Note that these
  724.    are hacks for compatibility with past mistakes and should be offensive
  725.    to any right thinking person.  They are offered solely to ease the pain
  726.    of running SLIP while users wait patiently for vendors to release PPP.
  727.  
  728.  
  729.    B.1  Living without a framing `type' byte
  730.  
  731.    The bizarre packet type numbers in sec. A.1 were chosen to allow a
  732.    `packet type' to be sent on lines where it is undesirable or impossible
  733.    to add an explicit type byte.  Note that the first byte of an IP packet
  734.    always contains `4' (the IP protocol version) in the top four bits.  And
  735.    that the most significant bit of the first byte of the compressed header
  736.    is ignored.  Using the packet types in sec. A.1, the type can be encoded
  737.    in the most significant bits of the outgoing packet using the code
  738.  
  739.  
  740.                     p->dat[0] |= sl_compress_tcp(p, comp);
  741.  
  742.     and decoded on the receive side by
  743.  
  744.                   if (p->dat[0] & 0x80)
  745.                           type = TYPE_COMPRESSED_TCP;
  746.                   else if (p->dat[0] >= 0x70) {
  747.                           type = TYPE_UNCOMPRESSED_TCP;
  748.                           p->dat[0] &=~ 0x30;
  749.                   } else
  750.                           type = TYPE_IP;
  751.                   status = sl_uncompress_tcp(p, type, comp);
  752.  
  753.  
  754. */
  755.  
  756. /*
  757.  
  758.    B.2  Backwards compatible SLIP servers
  759.  
  760.    The SLIP described in [12] doesn't include any mechanism that could be
  761.    used to automatically negotiate header compression.  It would be nice to
  762.    allow users of this SLIP to use header compression but, when users of
  763.    the two SLIP varients share a common server, it would be annoying and
  764.    difficult to manually configure both ends of each connection to enable
  765.    compression.  The following procedure can be used to avoid manual
  766.    configuration.
  767.  
  768.    Since there are two types of dial-in clients (those that implement
  769.    compression and those that don't) but one server for both types, it's
  770.    clear that the server will be reconfiguring for each new client session
  771.    but clients change configuration seldom if ever.  If manual
  772.    configuration has to be done, it should be done on the side that changes
  773.    infrequently --- the client.  This suggests that the server should
  774.    somehow learn from the client whether to use header compression.
  775.    Assuming symmetry (i.e., if compression is used at all it should be used
  776.    both directions) the server can use the receipt of a compressed packet
  777.    from some client to indicate that it can send compressed packets to that
  778.    client.  This leads to the following algorithm:
  779.  
  780.    There are two bits per line to control header compression:  allowed and
  781.    on.  If on is set, compressed packets are sent, otherwise not.  If
  782.    allowed is set, compressed packets can be received and, if an
  783.    UNCOMPRESSED_TCP packet arrives when on is clear, on will be set./49/
  784.    If a compressed packet arrives when allowed is clear, it will be
  785.    ignored.
  786.  
  787.    Clients are configured with both bits set (allowed is always set if on
  788.    is set) and the server starts each session with allowed set and on
  789.    clear.  The first compressed packet from the client (which must be a
  790.    UNCOMPRESSED_TCP packet) turns on compression for the server.
  791.  
  792. */
  793.