home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD2.bin / bbs / comm / amitcp-3.0ß2.lha / AmiTCP / src / devs / rhslip / cslip.c < prev    next >
C/C++ Source or Header  |  1994-01-28  |  19KB  |  665 lines

  1. /* $Id: cslip.c,v 1.1 1993/08/17 00:00:00 rhialto Exp $
  2.  *
  3.  *            COMPRESSED TCP HEADERS
  4.  *
  5.  * Reduce the 40 byte TCP header to as little as 5 or even 3 bytes
  6.  * (of which 2 bytes are the original TCP checksum).
  7.  *
  8.  * See RFC 1144 "Compression of TCP/IP Headers for Low-Speed Serial
  9.  * Links", V. Jacobson, February 1990, for the exciting details.
  10.  *
  11.  * The code in this file is derived from and very similar to the example
  12.  * implementation provided in RFC 1144, and is therefore sort-of covered
  13.  * by its copyright:
  14.  *
  15.  * Copyright (C) 1989 Regents of the University of California.
  16.  *
  17.  * This adaptation by Olaf 'Rhialto' Seibert.
  18.  * - fixed a number of sizeof(int) == 4 assumptions.
  19.  * - allow a few packets to be sent compressed before it is officially
  20.  *   enabled, so as to trigger the other side into compressed mode.
  21.  *
  22.  * Memory usage: < 3K of 68000 code, plus ~ 4K buffer space per line.
  23.  */
  24.  
  25. #include <string.h>
  26. #include "slip_device.h"
  27. #if DEBUG
  28. #include "syslog.h"
  29. #else
  30. #define debug(x)
  31. #endif
  32.  
  33. #define calloc(n,m)     AllocVec((n) * (m), MEMF_CLEAR)
  34. #define free(p)         FreeVec(p)
  35.  
  36. #ifndef EXEC_MEMORY_H
  37. #include <exec/memory.h>
  38. #endif
  39. #include <clib/exec_protos.h>
  40. #ifdef __SASC
  41. #include <pragmas/exec_pragmas.h>
  42. #endif
  43.  
  44. #define ihl(v_ihl)      lonibble(v_ihl) /* extract ip header length */
  45. #define tcp_offset(tcp)  ((u_char)(tcp)->offset >> DSHIFT)
  46.  
  47. /* Appendix A.2  Compression */
  48.  
  49. u_char
  50. sl_compress_tcp(m, comp)
  51. struct mbuf *m;
  52. struct slcompress *comp;
  53. {
  54.     register struct cstate *cs = comp->last_cs->cs_next;
  55.     register struct ip_header *ip = mtod(m, struct ip_header *);
  56.     register u_int hlen = ihl(ip->v_ihl);
  57.     register struct tcp_header *oth;    /* last TCP header */
  58.     register struct tcp_header *th;    /* current TCP header */
  59.     register u_long deltaS, deltaA;    /* general purpose temporaries */
  60.     register u_int changes = 0;     /* change mask */
  61.     u_char new_seq[16];         /* changes from last to current */
  62.     register u_char *cp = new_seq;
  63.  
  64.     debug((">sl_compress_tcp %lx %d\n", m->m_off, m->m_len));
  65.     /* Appendix B.2  Backwards compatible SLIP servers */
  66. #ifdef TRYCOUNT
  67.     if (comp->on == 0) {
  68.     debug(("<sl_compress_tcp: not on\n"));
  69.     return TYPE_IP;
  70.     }
  71. #else
  72.     if ((comp->flags & SLF_ON) == 0) {
  73.     debug(("<sl_compress_tcp: not on\n"));
  74.     return TYPE_IP;
  75.     }
  76. #endif
  77.  
  78.     if (ip->protocol != TCP_PTCL) {     /* Rhialto */
  79.     comp->sls_o_nontcp++;
  80.     debug(("<sl_compress_tcp: not tcp\n"));
  81.     return TYPE_IP;
  82.     }
  83.  
  84.     /*
  85.      * Bail if this is an IP fragment or if the TCP packet isn't
  86.      * `compressible' (i.e., ACK isn't set or some other control bit is
  87.      * set). (We assume that the caller has already made sure the packet
  88.      * is IP proto TCP).
  89.      */
  90.     if ((ip->fl_offs & htons(0x3fff)) || m->m_len < 40) {
  91.     comp->sls_o_tcp++;
  92.     debug(("<sl_compress_tcp: tcp frag\n"));
  93.     return TYPE_IP;
  94.     }
  95.  
  96.     th = (struct tcp_header *)&((int32 *) ip)[hlen];
  97.     if ((th->flags & (SYN | FIN | RST | ACK)) != ACK) {
  98.     comp->sls_o_tcp++;
  99.     debug(("<sl_compress_tcp: tcp flags\n"));
  100.     return TYPE_IP;
  101.     }
  102.  
  103.     /*
  104.      * Packet is compressible -- we're going to send either a
  105.      * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need to
  106.      * locate (or create) the connection state. Special case the most
  107.      * recently used connection since it's most likely to be used again &
  108.      * we don't have to do any reordering if it's used.
  109.      */
  110.     if (ip->source != cs->cs_ip.source ||
  111.     ip->dest != cs->cs_ip.dest ||
  112.     *(int32 *)th != cs->cs_hdr4[ihl(cs->cs_ip.v_ihl)]) {
  113.  
  114.     /*
  115.      * Wasn't the first -- search for it.
  116.      *
  117.      * States are kept in a circularly linked list with last_cs
  118.      * pointing to the end of the list. The list is kept in lru
  119.      * order by moving a state to the head of the list whenever
  120.      * it is referenced. Since the list is short and,
  121.      * empirically, the connection we want is almost always near
  122.      * the front, we locate states via linear search. If we don't
  123.      * find a state for the datagram, the oldest state is re-used.
  124.      */
  125.     register struct cstate *lcs;
  126.     register struct cstate *lastcs = comp->last_cs;
  127.  
  128.     do {
  129.         lcs = cs;
  130.         cs = cs->cs_next;
  131.         comp->sls_o_searches++;
  132.  
  133.         if (ip->source == cs->cs_ip.source &&
  134.         ip->dest == cs->cs_ip.dest &&
  135.         *(int32 *)th == cs->cs_hdr4[ihl(cs->cs_ip.v_ihl)])
  136.         goto found;
  137.     } while (cs != lastcs);
  138.  
  139.     /*
  140.      * Didn't find it -- re-use oldest cstate. Send an uncompressed
  141.      * packet that tells the other side what connection number
  142.      * we're using for this conversation. Note that since the
  143.      * state list is circular, the oldest state points to the newest
  144.      * and we only need to set last_cs to update the lru linkage.
  145.      */
  146.     comp->sls_o_misses++;
  147.     comp->last_cs = lcs;
  148.     hlen += tcp_offset(th); /* add tcp header length */
  149.     hlen *= sizeof(int32);
  150.  
  151.     goto uncompressed;
  152.  
  153.     found:
  154.     /* Found it -- move to the front on the connection list. */
  155.     if (lastcs == cs)
  156.         comp->last_cs = lcs;
  157.     else {
  158.         lcs->cs_next = cs->cs_next;
  159.         cs->cs_next = lastcs->cs_next;
  160.         lastcs->cs_next = cs;
  161.     }
  162.     }
  163.     debug((" sl_compress_tcp: found\n"));
  164. #ifdef TRYCOUNT
  165.     /*
  166.      * For found connections, try a few TCP_UNCOMPRESSED packets even if
  167.      * we're not SL_ON yet. (This doesn't happen on new connections;
  168.      * they will be TCP_UNCOMPRESSED regardless - FIXME.)
  169.      */
  170.     if (comp->on > 0) {
  171.     comp->on--;
  172.     debug((" sl_compress_tcp: trycount %d\n", comp->on));
  173.     goto uncompressed;
  174.     }
  175. #endif
  176.     /*
  177.      * Make sure that only what we expect to change changed. The 1st
  178.      * line of the 'if' checks the IP protocol version, header length &
  179.      * type of service. The 2nd line checks the "Don't fragment" bit.
  180.      * The 3rd line checks the time-to-live and protocol (the protocol
  181.      * check is unnecessary but costless). The 4th line checks the TCP
  182.      * header length. The 5th line checks IP options, if any. The 6th
  183.      * line checks TCP options, if any. If any of these things are
  184.      * different between the previous & current datagram, we send the
  185.      * current datagram "uncompressed".
  186.      */
  187.     oth = (struct tcp_header *) &cs->cs_hdr4[hlen];
  188.     deltaS = hlen;
  189.     hlen += tcp_offset(th);
  190.     hlen *= sizeof(int32);
  191.  
  192.     if (((u_short *) ip)[0] != ((u_short *) &cs->cs_ip)[0] || /* v_ihl,tos */
  193.     ((u_short *) ip)[3] != ((u_short *) &cs->cs_ip)[3] || /* fl_offs */
  194.     ((u_short *) ip)[4] != ((u_short *) &cs->cs_ip)[4] || /* ttl, protocol */
  195.     th->offset != oth->offset ||
  196.     (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) * sizeof(int32))) ||
  197.     (tcp_offset(th) > 5 && BCMP(th + 1, oth + 1, (tcp_offset(th) - 5) * sizeof(int32)))) {
  198.     debug((" sl_compress_tcp: header changed\n"));
  199.     goto uncompressed;
  200.     }
  201.  
  202.     /*
  203.      * Figure out which of the changing fields changed. The receiver
  204.      * expects changes in the order: urgent, window, ack, seq.
  205.      */
  206.     if (th->flags & URG) {
  207.     deltaS = ntohs(th->up);
  208.     ENCODEZ(deltaS);
  209.     changes |= NEW_U;
  210.     } else if (th->up != oth->up) {
  211.     /*
  212.      * argh! URG not set but urp changed -- a sensible
  213.      * implementation should never do this but RFC 793 doesn't
  214.      * prohibit the change so we have to deal with it.
  215.      */
  216.     debug((" sl_compress_tcp: up changed\n"));
  217.     goto uncompressed;
  218.     }
  219.  
  220.     if (deltaS = (u_short) (ntohs(th->wnd) - ntohs(oth->wnd))) {
  221.     ENCODE(deltaS);
  222.     changes |= NEW_W;
  223.     }
  224.     if (deltaA = ntohs(th->ack) - ntohs(oth->ack)) {
  225.     if (deltaA > 0xffff)
  226.         goto uncompressed;
  227.     ENCODE(deltaA);
  228.     changes |= NEW_A;
  229.     }
  230.     if (deltaS = ntohs(th->seq) - ntohs(oth->seq)) {
  231.     if (deltaS > 0xffff)
  232.         goto uncompressed;
  233.     ENCODE(deltaS);
  234.     changes |= NEW_S;
  235.     }
  236.     /*
  237.      * Look for the special-case encodings.
  238.      */
  239.     switch (changes) {
  240.  
  241.     case 0:
  242.     /*
  243.      * Nothing changed. If this packet contains data and the last
  244.      * one didn't, this is probably a data packet following an
  245.      * ack (normal on an interactive connection) and we send it
  246.      * compressed. Otherwise it's probably a retransmit,
  247.      * retransmitted ack or window probe. Send it uncompressed
  248.      * in case the other side missed the compressed version.
  249.      */
  250.     if (ip->length != cs->cs_ip.length &&
  251.         ntohs(cs->cs_ip.length) == hlen)
  252.         break;
  253.  
  254.     debug((" sl_compress_tcp: retransmission ->\n"));
  255.     /* fall through */
  256.  
  257.     case