home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / internet / netlite / NET / c / TCPSUBR < prev    next >
Text File  |  1993-03-15  |  8KB  |  268 lines

  1. #include <stdlib.h>
  2. #include "global.h"
  3. #include "timer.h"
  4. #include "mbuf.h"
  5. #include "misc.h"
  6. #include "netuser.h"
  7. #include "internet.h"
  8. #include "tcp.h"
  9.  
  10. static int16 hash_tcb(struct connection *);
  11.  
  12. struct tcb *tcbs[NTCB];
  13. int16 tcp_mss = DEF_MSS;        /* Maximum segment size to be sent with SYN */
  14. int32 tcp_irtt = DEF_RTT;       /* Initial guess at round trip time */
  15.  
  16. /* Lookup connection, return TCB pointer or NULLTCB if nonexistant */
  17. struct tcb *lookup_tcb(struct connection *conn)
  18. {
  19.         register struct tcb *tcb;
  20.  
  21.         tcb = tcbs[hash_tcb(conn)];
  22.         while(tcb != NULLTCB){
  23.                 /* Yet another structure compatibility hack */
  24.                 if(conn->local.address == tcb->conn.local.address
  25.                  && conn->remote.address == tcb->conn.remote.address
  26.                  && conn->local.port == tcb->conn.local.port
  27.                  && conn->remote.port == tcb->conn.remote.port)
  28.                         break;
  29.                 tcb = tcb->next;
  30.         }
  31.         return tcb;
  32. }
  33.  
  34. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  35. struct tcb *create_tcb(struct connection *conn)
  36. {
  37.         register struct tcb *tcb;
  38.  
  39.         if((tcb = lookup_tcb(conn)) != NULLTCB)
  40.                 return tcb;
  41.         if((tcb = (struct tcb *)calloc(1,sizeof (struct tcb))) == NULLTCB)
  42.                 return NULLTCB;
  43.         tcb->conn = *conn;
  44.  
  45.         tcb->cwind = tcb->mss = tcp_mss;
  46.         tcb->ssthresh = 65535;
  47.         tcb->srtt = tcp_irtt;
  48.         /* Initialize timer intervals */
  49.         tcb->timer.start = tcb->srtt / MSPTICK;
  50.         tcb->timer.func = tcp_timeout;
  51.         tcb->timer.arg = (char *)tcb;
  52.         tcb->rtt_timer.start = MAX_TIME; /* Largest possible value */
  53.  
  54.         link_tcb(tcb);
  55.         return tcb;
  56. }
  57.  
  58. /* Close our TCB */
  59. void close_self(register struct tcb *tcb, char reason)
  60. {
  61.         struct reseq *rp,*rp1;
  62.  
  63.         stop_timer(&tcb->timer);
  64.         stop_timer(&tcb->rtt_timer);
  65.         tcb->reason = reason;
  66.  
  67.         /* Flush reassembly queue; nothing more can arrive */
  68.         for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  69.                 rp1 = rp->next;
  70.                 free_p(rp->bp);
  71.                 free((char *)rp);
  72.         }
  73.         tcb->reseq = NULLRESEQ;
  74.         setstate(tcb,CLOSED);
  75. }
  76.  
  77. /* Determine initial sequence number */
  78. int32 iss(void)
  79. {
  80.         static int32 seq;
  81.  
  82.         seq += 250000;
  83.         return seq;
  84. }
  85.  
  86. /* Sequence number comparisons
  87.  * Return true if x is between low and high inclusive,
  88.  * false otherwise
  89.  */
  90. int seq_within(int32 x, int32 low, int32 high)
  91. {
  92.         if(low <= high){
  93.                 if(low <= x && x <= high)
  94.                         return 1;
  95.         } else {
  96.                 if(low >= x && x >= high)
  97.                         return 1;
  98.         }
  99.         return 0;
  100. }
  101. int seq_lt(int32 x, int32 y)
  102. {
  103.         return (x-y) < 0;
  104. }
  105. int seq_le(int32 x, int32 y)
  106. {
  107.         return (x-y) <= 0;
  108. }
  109. int seq_gt(int32 x, int32 y)
  110. {
  111.         return (x-y) > 0;
  112. }
  113. int seq_ge(int32 x, int32 y)
  114. {
  115.         return (x-y) >= 0;
  116. }
  117.  
  118. /* Hash a connect structure into the hash chain header array */
  119. static int16 hash_tcb(struct connection *conn)
  120. {
  121.         register int16 hval;
  122.  
  123.         /* Compute hash function on connection structure */
  124.         hval = hiword(conn->remote.address);
  125.         hval ^= loword(conn->remote.address);
  126.         hval ^= hiword(conn->local.address);
  127.         hval ^= loword(conn->local.address);
  128.         hval ^= conn->remote.port;
  129.         hval ^= conn->local.port;
  130.         hval %= NTCB;
  131.         return hval;
  132. }
  133. /* Insert TCB at head of proper hash chain */
  134. void link_tcb(register struct tcb *tcb)
  135. {
  136.         register struct tcb **tcbhead;
  137.  
  138.         tcb->prev = NULLTCB;
  139.         tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  140.         tcb->next = *tcbhead;
  141.         if(tcb->next != NULLTCB){
  142.                 tcb->next->prev = tcb;
  143.         }
  144.         *tcbhead = tcb;
  145. }
  146. /* Remove TCB from whatever hash chain it may be on */
  147. void unlink_tcb(register struct tcb *tcb)
  148. {
  149.         register struct tcb **tcbhead;
  150.  
  151.         tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  152.         if(*tcbhead == tcb)
  153.                 *tcbhead = tcb->next;   /* We're the first one on the chain */
  154.         if(tcb->prev != NULLTCB)
  155.                 tcb->prev->next = tcb->next;
  156.         if(tcb->next != NULLTCB)
  157.                 tcb->next->prev = tcb->prev;
  158. }
  159. void setstate(register struct tcb *tcb, register char newstate)
  160. {
  161.         register char oldstate;
  162.  
  163.         oldstate = tcb->state;
  164.         tcb->state = newstate;
  165.         if(tcb->s_upcall){
  166.                 (*tcb->s_upcall)(tcb,oldstate,newstate);
  167.         }
  168.         /* Notify the user that he can begin sending data */
  169.         if(tcb->t_upcall && newstate == ESTABLISHED){
  170.                 (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  171.         }
  172. }
  173. /* Convert TCP header in host format into mbuf ready for transmission,
  174.  * link in data (if any), and compute checksum
  175.  */
  176. struct mbuf *htontcp(struct tcp *tcph, struct mbuf *data, struct pseudo_header *ph)
  177. {
  178.         int16 hdrlen;
  179.         struct mbuf *bp;
  180.         register char *cp;
  181.         int16 csum;
  182.  
  183.         hdrlen = (tcph->mss != 0) ? TCPLEN + MSS_LENGTH : TCPLEN;
  184.         
  185.         if((bp = pushdown(data,hdrlen)) == NULLBUF){
  186.                 free_p(data);
  187.                 return NULLBUF;
  188.         }
  189.         cp = bp->data;
  190.         cp = put16(cp,tcph->source);
  191.         cp = put16(cp,tcph->dest);
  192.         cp = put32(cp,tcph->seq);
  193.         cp = put32(cp,tcph->ack);
  194.         *cp++ = hdrlen << 2;    /* Offset field */
  195.         *cp++ = tcph->flags;
  196.         cp = put16(cp,tcph->wnd);
  197.         *cp++ = 0;      /* Zero out checksum field */
  198.         *cp++ = 0;
  199.         cp = put16(cp,tcph->up);
  200.  
  201.         if(tcph->mss != 0){
  202.                 *cp++ = MSS_KIND;
  203.                 *cp++ = MSS_LENGTH;
  204.                 cp = put16(cp,tcph->mss);
  205.         }
  206.         csum = cksum(ph,bp,ph->length);
  207.         cp = &bp->data[16];     /* Checksum field */    
  208.         *cp++ = csum >> 8;
  209.         *cp = csum;
  210.  
  211.         return bp;
  212. }
  213. /* Pull TCP header off mbuf */
  214. int ntohtcp(struct tcp *tcph, struct mbuf **bpp)
  215. {
  216.         int16 hdrlen;
  217.         int16 i,optlen;
  218.  
  219.         tcph->source = pull16(bpp);
  220.         tcph->dest = pull16(bpp);
  221.         tcph->seq = pull32(bpp);
  222.         tcph->ack = pull32(bpp);
  223.         if(*bpp == NULLBUF)
  224.                 /* Buffer too short to pull off header length */
  225.                 return -1;
  226.         hdrlen = (pullchar(bpp) & 0xf0) >> 2;
  227.         tcph->flags = pullchar(bpp);
  228.         tcph->wnd = pull16(bpp);
  229.         (void)pull16(bpp);      /* Skip checksum */
  230.         tcph->up = pull16(bpp);
  231.         tcph->mss = 0;
  232.  
  233.         /* Check for option field. Only space for one is allowed, but
  234.          * since there's only one TCP option (MSS) this isn't a problem
  235.          */
  236.         if(hdrlen < TCPLEN)
  237.                 return -1;      /* Header smaller than legal minimum */
  238.         if(hdrlen == TCPLEN)
  239.                 return hdrlen;  /* No options, all done */
  240.  
  241.         if(hdrlen > len_mbuf(*bpp) + TCPLEN){
  242.                 /* Remainder too short for options length specified */
  243.                 return -1;
  244.         }
  245.         /* Process options */
  246.         for(i=TCPLEN; i < hdrlen;){
  247.                 switch(pullchar(bpp)){
  248.                 case EOL_KIND:
  249.                         i++;
  250.                         goto eol;       /* End of options list */
  251.                 case NOOP_KIND:
  252.                         i++;
  253.                         break;
  254.                 case MSS_KIND:
  255.                         optlen = pullchar(bpp);
  256.                         if(optlen == MSS_LENGTH)
  257.                                 tcph->mss = pull16(bpp);
  258.                         i += optlen;
  259.                         break;
  260.                 }
  261.         }
  262. eol:
  263.         /* Get rid of any padding */
  264.         if(i < hdrlen)
  265.                 pullup(bpp,NULLCHAR,hdrlen - i);
  266.         return hdrlen;
  267. }
  268.