home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / internet / tcpipsrc / Drivers / c / sl_compres < prev    next >
Text File  |  1995-02-20  |  29KB  |  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