home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / misc / tcpipsrc / tcpsubr.c < prev    next >
C/C++ Source or Header  |  1991-01-26  |  8KB  |  374 lines

  1. /* Low level TCP routines:
  2.  *  control block management
  3.  *  sequence number logical operations
  4.  *  state transitions
  5.  *  RTT cacheing
  6.  *  garbage collection
  7.  *
  8.  * Copyright 1991 Phil Karn, KA9Q
  9.  */
  10. #include <stdio.h>
  11. #include "global.h"
  12. #include "timer.h"
  13. #include "mbuf.h"
  14. #include "netuser.h"
  15. #include "internet.h"
  16. #include "tcp.h"
  17. #include "ip.h"
  18.  
  19. static int16 hash_tcb __ARGS((struct connection *conn));
  20.  
  21. /* TCP connection states */
  22. char *Tcpstates[] = {
  23.     "",
  24.     "Closed",
  25.     "Listen",
  26.     "SYN sent",
  27.     "SYN received",
  28.     "Established",
  29.     "FIN wait 1",
  30.     "FIN wait 2",
  31.     "Close wait",
  32.     "Last ACK",
  33.     "Closing",
  34.     "Time wait"
  35. };
  36.  
  37. /* TCP closing reasons */
  38. char *Tcpreasons[] = {
  39.     "Normal",
  40.     "Reset/Refused",
  41.     "Timeout",
  42.     "ICMP"
  43. };
  44. struct tcb *Tcbs[NTCB];
  45. int16 Tcp_mss = DEF_MSS;    /* Maximum segment size to be sent with SYN */
  46. int32 Tcp_irtt = DEF_RTT;    /* Initial guess at round trip time */
  47. int Tcp_trace;            /* State change tracing flag */
  48. int Tcp_syndata;
  49. struct tcp_rtt Tcp_rtt[RTTCACHE];
  50. struct mib_entry Tcp_mib[] = {
  51.     NULLCHAR,        0,
  52.     "tcpRtoAlgorithm",    4,    /* Van Jacobsen's algorithm */
  53.     "tcpRtoMin",        0,    /* No lower bound */
  54.     "tcpRtoMax",        MAXINT32,    /* No upper bound */
  55.     "tcpMaxConn",        -1L,    /* No limit */
  56.     "tcpActiveOpens",    0,
  57.     "tcpPassiveOpens",    0,
  58.     "tcpAttemptFails",    0,
  59.     "tcpEstabResets",    0,
  60.     "tcpCurrEstab",        0,
  61.     "tcpInSegs",        0,
  62.     "tcpOutSegs",        0,
  63.     "tcpRetransSegs",    0,
  64.     NULLCHAR,        0,    /* Connection state goes here */
  65.     "tcpInErrs",        0,
  66.     "tcpOutRsts",        0,
  67. };
  68.  
  69.  
  70. /* Lookup connection, return TCB pointer or NULLTCB if nonexistant */
  71. struct tcb *
  72. lookup_tcb(conn)
  73. struct connection *conn;
  74. {
  75.     register struct tcb *tcb;
  76.  
  77.     tcb = Tcbs[hash_tcb(conn)];
  78.     while(tcb != NULLTCB){
  79.         /* Yet another structure compatibility hack */
  80.         if(conn->local.address == tcb->conn.local.address
  81.          && conn->remote.address == tcb->conn.remote.address
  82.          && conn->local.port == tcb->conn.local.port
  83.          && conn->remote.port == tcb->conn.remote.port)
  84.             break;
  85.         tcb = tcb->next;
  86.     }
  87.     return tcb;
  88. }
  89.  
  90. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  91. struct tcb *
  92. create_tcb(conn)
  93. struct connection *conn;
  94. {
  95.     register struct tcb *tcb;
  96.     struct tcp_rtt *tp;
  97.  
  98.     if((tcb = lookup_tcb(conn)) != NULLTCB)
  99.         return tcb;
  100.     tcb = (struct tcb *)callocw(1,sizeof (struct tcb));
  101.     ASSIGN(tcb->conn,*conn);
  102.  
  103.     tcb->state = TCP_CLOSED;
  104.     tcb->cwind = tcb->mss = Tcp_mss;
  105.     tcb->ssthresh = 65535;
  106.     if((tp = rtt_get(tcb->conn.remote.address)) != NULLRTT){
  107.         tcb->srtt = tp->srtt;
  108.         tcb->mdev = tp->mdev;
  109.     } else {
  110.         tcb->srtt = Tcp_irtt;    /* mdev = 0 */
  111.     }
  112.     /* Initialize timer intervals */
  113.     set_timer(&tcb->timer,tcb->srtt);
  114.     tcb->timer.func = tcp_timeout;
  115.     tcb->timer.arg = tcb;
  116.  
  117.     link_tcb(tcb);
  118.     return tcb;
  119. }
  120.  
  121. /* Close our TCB */
  122. void
  123. close_self(tcb,reason)
  124. register struct tcb *tcb;
  125. int reason;
  126. {
  127.     struct reseq *rp1;
  128.     register struct reseq *rp;
  129.  
  130.     if(tcb == NULLTCB)
  131.         return;
  132.  
  133.     stop_timer(&tcb->timer);
  134.     tcb->reason = reason;
  135.  
  136.     /* Flush reassembly queue; nothing more can arrive */
  137.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  138.         rp1 = rp->next;
  139.         free_p(rp->bp);
  140.         free((char *)rp);
  141.     }
  142.     tcb->reseq = NULLRESEQ;
  143.     setstate(tcb,TCP_CLOSED);
  144. }
  145.  
  146. /* Sequence number comparisons
  147.  * Return true if x is between low and high inclusive,
  148.  * false otherwise
  149.  */
  150. int
  151. seq_within(x,low,high)
  152. register int32 x,low,high;
  153. {
  154.     if(low <= high){
  155.         if(low <= x && x <= high)
  156.             return 1;
  157.     } else {
  158.         if(low >= x && x >= high)
  159.             return 1;
  160.     }
  161.     return 0;
  162. }
  163. int
  164. seq_lt(x,y)
  165. register int32 x,y;
  166. {
  167.     return (long)(x-y) < 0;
  168. }
  169. #ifdef    notdef
  170. int
  171. seq_le(x,y)
  172. register int32 x,y;
  173. {
  174.     return (long)(x-y) <= 0;
  175. }
  176. #endif    /* notdef */
  177. int
  178. seq_gt(x,y)
  179. register int32 x,y;
  180. {
  181.     return (long)(x-y) > 0;
  182. }
  183. int
  184. seq_ge(x,y)
  185. register int32 x,y;
  186. {
  187.     return (long)(x-y) >= 0;
  188. }
  189.  
  190. /* Hash a connect structure into the hash chain header array */
  191. static int16
  192. hash_tcb(conn)
  193. struct connection *conn;
  194. {
  195.     register int16 hval;
  196.  
  197.     /* Compute hash function on connection structure */
  198.     hval = hiword(conn->remote.address);
  199.     hval ^= loword(conn->remote.address);
  200. #ifdef    notdef    /* Never changes, so not really needed */
  201.     hval ^= hiword(conn->local.address);
  202.     hval ^= loword(conn->local.address);
  203. #endif
  204.     hval ^= conn->remote.port;
  205.     hval ^= conn->local.port;
  206.     return (int16)(hval % NTCB);
  207. }
  208. /* Insert TCB at head of proper hash chain */
  209. void
  210. link_tcb(tcb)
  211. register struct tcb *tcb;
  212. {
  213.     register struct tcb **tcbhead;
  214.  
  215.     tcb->prev = NULLTCB;
  216.     tcbhead = &Tcbs[hash_tcb(&tcb->conn)];
  217.     tcb->next = *tcbhead;
  218.     if(tcb->next != NULLTCB)
  219.         tcb->next->prev = tcb;
  220.  
  221.     *tcbhead = tcb;
  222. }
  223. /* Remove TCB from whatever hash chain it may be on */
  224. void
  225. unlink_tcb(tcb)
  226. register struct tcb *tcb;
  227. {
  228.     register struct tcb **tcbhead;
  229.  
  230.     tcbhead = &Tcbs[hash_tcb(&tcb->conn)];
  231.     if(tcb->prev == NULLTCB)
  232.         *tcbhead = tcb->next;    /* We're the first one on the chain */
  233.     else
  234.         tcb->prev->next = tcb->next;
  235.     if(tcb->next != NULLTCB)
  236.         tcb->next->prev = tcb->prev;
  237. }
  238. void
  239. setstate(tcb,newstate)
  240. register struct tcb *tcb;
  241. register int newstate;
  242. {
  243.     register char oldstate;
  244.  
  245.     oldstate = tcb->state;
  246.     tcb->state = newstate;
  247.     if(Tcp_trace)
  248.         printf("TCB %lx %s -> %s\n",ptol(tcb),
  249.          Tcpstates[oldstate],Tcpstates[newstate]);
  250.  
  251.     /* Update MIB variables */
  252.     switch(oldstate){
  253.     case TCP_CLOSED:
  254.         if(newstate == TCP_SYN_SENT)
  255.             tcpActiveOpens++;
  256.         break;
  257.     case TCP_LISTEN:
  258.         if(newstate == TCP_SYN_RECEIVED)
  259.             tcpPassiveOpens++;
  260.         break;
  261.     case TCP_SYN_SENT:
  262.         if(newstate == TCP_CLOSED)
  263.             tcpAttemptFails++; 
  264.         break;
  265.     case TCP_SYN_RECEIVED:
  266.         switch(newstate){
  267.         case TCP_CLOSED:
  268.         case TCP_LISTEN:
  269.             tcpAttemptFails++; 
  270.             break;
  271.         }
  272.         break;
  273.     case TCP_ESTABLISHED:
  274.     case TCP_CLOSE_WAIT:
  275.         switch(newstate){
  276.         case TCP_CLOSED:
  277.         case TCP_LISTEN:
  278.             tcpEstabResets++;
  279.             break;
  280.         }
  281.         tcpCurrEstab--;
  282.         break;
  283.     }
  284.     if(newstate == TCP_ESTABLISHED || newstate == TCP_CLOSE_WAIT)
  285.         tcpCurrEstab++;
  286.  
  287.     if(tcb->s_upcall)
  288.         (*tcb->s_upcall)(tcb,oldstate,newstate);
  289.  
  290.     switch(newstate){
  291.     case TCP_SYN_RECEIVED:    /***/
  292.     case TCP_ESTABLISHED:
  293.         /* Notify the user that he can begin sending data */
  294.         if(tcb->t_upcall)
  295.             (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  296.         break;
  297.     }
  298. }
  299. /* Round trip timing cache routines.
  300.  * These functions implement a very simple system for keeping track of
  301.  * network performance for future use in new connections.
  302.  * The emphasis here is on speed of update (rather than optimum cache hit
  303.  * ratio) since rtt_add is called every time a TCP connection updates
  304.  * its round trip estimate.
  305.  */
  306. void
  307. rtt_add(addr,rtt)
  308. int32 addr;        /* Destination IP address */
  309. int32 rtt;
  310. {
  311.     register struct tcp_rtt *tp;
  312.     int32 abserr;
  313.  
  314.     if(addr == 0)
  315.         return;
  316.     tp = &Tcp_rtt[(unsigned short)addr % RTTCACHE];
  317.     if(tp->addr != addr){
  318.         /* New entry */
  319.         tp->addr = addr;
  320.         tp->srtt = rtt;
  321.         tp->mdev = 0;
  322.     } else {
  323.         /* Run our own SRTT and MDEV integrators, with rounding */
  324.         abserr = (rtt > tp->srtt) ? rtt - tp->srtt : tp->srtt - rtt;
  325.         tp->srtt = ((AGAIN-1)*tp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
  326.         tp->mdev = ((DGAIN-1)*tp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
  327.     }
  328. }
  329. struct tcp_rtt *
  330. rtt_get(addr)
  331. int32 addr;
  332. {
  333.     register struct tcp_rtt *tp;
  334.  
  335.     if(addr == 0)
  336.         return NULLRTT;
  337.     tp = &Tcp_rtt[(unsigned short)addr % RTTCACHE];
  338.     if(tp->addr != addr)
  339.         return NULLRTT;
  340.     return tp;
  341. }
  342.  
  343. /* TCP garbage collection - called by storage allocator when free space
  344.  * runs low. The send and receive queues are crunched. If the situation
  345.  * is red, the resequencing queue is discarded; otherwise it is
  346.  * also crunched.
  347.  */
  348. void
  349. tcp_garbage(red)
  350. int red;
  351. {
  352.     register struct tcb *tcb;
  353.     int i;
  354.     struct reseq *rp,*rp1;
  355.  
  356.     for(i=0;i<NTCB;i++){
  357.         for(tcb = Tcbs[i];tcb != NULLTCB;tcb = tcb->next){
  358.             mbuf_crunch(&tcb->rcvq);
  359.             mbuf_crunch(&tcb->sndq);
  360.             for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  361.                 rp1 = rp->next;
  362.                 if(red){
  363.                     free_p(rp->bp);
  364.                     free((char *)rp);
  365.                 } else {
  366.                     mbuf_crunch(&rp->bp);
  367.                 }
  368.             }
  369.             if(red)
  370.                 tcb->reseq = NULLRESEQ;
  371.         }
  372.     }
  373. }
  374.