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