home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / t / tel2305s.zip / ENGINE / TCP.C < prev    next >
C/C++ Source or Header  |  1992-04-08  |  20KB  |  600 lines

  1. /*
  2. *    TCP.C
  3. *
  4. *    TCP level routines
  5. *
  6. ****************************************************************************
  7. *                                                                          *
  8. *      part of:                                                            *
  9. *      TCP/UDP/ICMP/IP Network kernel for NCSA Telnet                      *
  10. *      by Tim Krauskopf                                                    *
  11. *                                                                          *
  12. *      National Center for Supercomputing Applications                     *
  13. *      152 Computing Applications Building                                 *
  14. *      605 E. Springfield Ave.                                             *
  15. *      Champaign, IL  61820                                                *
  16. *                                                                          *
  17. *      This program is in the public domain.                               *
  18. *                                                                          *
  19. ****************************************************************************
  20. *
  21. *    Revision history:
  22. *
  23. *    10/86 started
  24. *   2/88 mods for int16/int32
  25. *    5/89    clean up for 2.3 release, JKM    
  26. *
  27. */
  28.  
  29. /*
  30.  *    Includes
  31.  */
  32. #include <stdio.h>
  33. #include "protocol.h"
  34. #include "data.h"
  35. #include "externs.h"
  36.  
  37. static void checkfin(struct port *,TCPKT *);
  38. static int estab1986(struct port *,TCPKT *,int ,int );
  39. static int ackcheck(struct port *,TCPKT *,int );
  40. static void checkmss(struct port *,TCPKT *,int );
  41. static int tcpreset(TCPKT *);
  42. static int tcpdo(struct port *,TCPKT *,int ,int);
  43.  
  44. /*
  45.  *    Semi-Global Vars
  46.  */
  47. static int pnum;                                    /* port number */
  48.  
  49. /************************************************************************
  50. *
  51. *    tcpinterpret ( p, tlen ) 
  52. *
  53. *    Called when a packet comes in and passes the IP checksum and is ov
  54. * TCP protocol type.  Check to see if we have an open connection on
  55. * the appropriate port and stuff it in the right buffer
  56. *
  57. */
  58. int tcpinterpret(TCPKT *p,int tlen)
  59. {
  60.     uint i,myport,hlen,hisport;
  61.     struct port *prt;
  62.  
  63. /*
  64. *  checksum
  65. *    First, fill the pseudo header with its fields, then run our
  66. *  checksum to confirm it.
  67. *
  68. */
  69.     if(p->t.check) {
  70.         movebytes(tcps.source,p->i.ipsource,8);  /* move both addresses */
  71.         tcps.z=0;
  72.         tcps.proto=p->i.protocol;
  73.         tcps.tcplen=intswap(tlen);            /* byte-swapped length */
  74.         if(tcpcheck((char *)&tcps,(char *)&p->t,tlen)) {    /* compute checksum */
  75.             netposterr(400);
  76.             return(2);
  77.           } /* end if */
  78.       } /* end if */
  79. /*
  80. *  find the port which is associated with the incoming packet
  81. *  First try open connections, then try listeners
  82. */
  83.     myport=intswap(p->t.dest);
  84.     hisport=intswap(p->t.source);
  85.     hlen=p->t.hlen>>2;                /* bytes offset to data */
  86.     for(i=0; i<NPORTS; i++) {
  87.         prt=portlist[i];
  88.         if(prt!=NULL && prt->in.port==myport && prt->out.port==hisport) {
  89.             pnum=i;
  90.             return(tcpdo(prt,p,tlen,hlen));
  91.           } /* end if */
  92.       } /* end for */
  93. /*
  94. *  check to see if the incoming packet should go to a listener
  95. */
  96.     for(i=0; i<NPORTS; i++) {
  97.         prt=portlist[i];
  98.         if(prt!=NULL && !prt->out.port && prt->in.port==myport && (p->t.flags&TSYN)) {
  99.             pnum=i;
  100.             return(tcpdo(prt,p,tlen,hlen));
  101.           } /* end if */
  102.       } /* end for */
  103. /*
  104. *  no matching port was found to handle this packet, reject it
  105. */
  106.     tcpreset(p);                /* tell them they are crazy */
  107.     if(!(p->t.flags&TSYN)) {    /* no error message if it is a SYN */
  108.         netposterr(407);        /* invalid port for incoming packet */
  109.         inv_port_err(1,myport,p->i.ipdest);
  110.       } /* end if */
  111.     return(1);                  /* no port matches */
  112. }   /* end tcpinterpret() */
  113.  
  114. /**********************************************************************/
  115. /*
  116. *    tcpdo ( prt, p, tlen, hlen )
  117. *
  118. *    Deliver the incoming packet.
  119. *
  120. */
  121. static int tcpdo(struct port *prt,TCPKT *p,int tlen,int hlen)
  122. {
  123.     switch(prt->state) {
  124.         case SLISTEN:                    /* waiting for remote connection */
  125.             if(p->t.flags&TRESET)   /* ignore Resets on a connection in LISTEN state */
  126.                 break;
  127.  
  128.             if(p->t.flags&TSYN) {    /* receive SYN */
  129. /*
  130. *   remember anything important from the incoming TCP header 
  131. */
  132.                 prt->out.size=intswap(p->t.window);    /* credit window */
  133.                 prt->out.port=intswap(p->t.source);
  134.                 prt->in.nxt=longswap(p->t.seq)+1;
  135. /*
  136. *  set the necessary fields in the outgoing TCP packet
  137. */
  138.                 prt->tcpout.t.dest=p->t.source;
  139.                 prt->tcpout.t.ack=longswap(prt->in.nxt);
  140.                 prt->tcpout.t.flags=TSYN|TACK;
  141.                 prt->tcpout.t.hlen=24<<2;
  142. /*
  143. *  note that the maxmimum segment size is installed by 'netlisten()'
  144. *  hence the header length is 24, not 20
  145. */
  146. /*
  147. *  initialize all of the low-level transmission stuff(IP and lower)
  148. */
  149.                 movebytes(prt->tcps.dest,p->i.ipsource,4);
  150.                 movebytes(prt->tcpout.i.ipdest,p->i.ipsource,4);
  151.                 movebytes(prt->tcpout.d.dest,p->d.me,DADDLEN);
  152. #ifdef OLD_WAY
  153. /*
  154. *   look up address in the arp cache if using Localtalk encapsulation
  155. */
  156.                 if(!nnemac) {
  157.                     unsigned char *pc;
  158.  
  159.                     pc=getdlayer(p->i.ipsource);
  160.                     if(pc!=NULL)
  161.                         movebytes(prt->tcpout.d.dest,pc,DADDLEN);
  162.                     else
  163.                         return(0);        /* no hope this time */
  164.                   }
  165. #endif
  166.                 tcpsend(prt,4);
  167.                 prt->state=SSYNR;        /* syn received */
  168.               } /* end if */
  169.             break;
  170.  
  171.         case SSYNR:
  172.             if(!(p->t.flags&TACK)) {
  173.                 tcpsend(prt,4);
  174.                 break;                    /* not the right one */
  175.               } /* end if */
  176.             prt->tcpout.t.hlen=20<<2;
  177.             prt->out.lasttime=n_clicks();           /* don't need response */
  178.             prt->out.nxt++;                            /* count SYN as sent */
  179.             prt->out.ack=longswap(p->t.ack);         /* starting ACK value */
  180.             prt->out.size=intswap(p->t.window);    /* allowed window */
  181.             prt->tcpout.t.flags=TACK;        /* starting ACK flag */
  182.             prt->state=SEST;                /* drop through to established */
  183.             netputevent(CONCLASS,CONOPEN,pnum);
  184.             checkmss(prt,p,hlen);            /* see if MSS option is there */
  185.                                             /* fall through */
  186.  
  187.         case SEST:            /* normal data transmission */    
  188. /*
  189. *  check and accept a possible piggybacked ack
  190. */
  191.             ackcheck(prt,p,pnum);
  192.             estab1986(prt,p,tlen,hlen);
  193.             return(0);
  194.  
  195.         case SSYNS:                /* check to see if it ACKS correctly */
  196.                                 /* remember that tcpout is pre-set-up */
  197.             if(p->t.flags&TACK) {        /* It is ACKING us */
  198.                 if((uint32)longswap(p->t.ack)!=(prt->out.nxt)) {
  199.                     netposterr(401);
  200.                     return(1);
  201.                   } /* end if */
  202.               } /* end if */
  203.             if(p->t.flags&TRESET) {
  204.                 netposterr(507);
  205.                 prt->state=SCLOSED;
  206.                 netputuev(CONCLASS,CONCLOSE,pnum);
  207.                 return(1);
  208.               } /* end if */
  209.             if(p->t.flags&TSYN) {            /* need to send ACK */
  210.                 prt->tcpout.t.flags=TACK;
  211.                 prt->in.nxt=longswap(p->t.seq) + 1;
  212.                 prt->tcpout.t.ack=longswap(prt->in.nxt);
  213.                 prt->out.ack=longswap(p->t.ack);
  214.                 prt->out.size=intswap(p->t.window);    /* credit window */
  215.                 prt->out.lasttime=0L;
  216.                 if(p->t.flags&TACK) {
  217.                     prt->state=SEST;
  218.                     netputevent(CONCLASS,CONOPEN,pnum);
  219.                     checkmss(prt,p,hlen);
  220.                   } /* end if */
  221.                 else
  222.                     prt->state=SSYNR;        /* syn received */
  223.               } /* end if */
  224.             break;
  225.  
  226.         case SCWAIT:
  227.             ackcheck(prt,p,pnum);
  228.             if(!prt->in.contain) {
  229.                 prt->tcpout.t.flags=TFIN|TACK;
  230.                 prt->out.lasttime=0L;
  231.                 prt->state=SLAST;
  232.               } /* end if */
  233.             break;
  234.  
  235.         case SLAST:            /* check ack of FIN, or reset to see if we are done */
  236.             if((p->t.flags&TRESET) || ((uint32)longswap(p->t.ack)==(prt->out.nxt+1)))
  237.                 prt->state=SCLOSED;
  238.             break;
  239.  
  240.         case SFW1:  /* waiting for ACK of FIN */
  241.             /* throw away data */
  242.             prt->in.nxt=longswap(p->t.seq)+tlen-hlen;
  243.             if(p->t.flags&TRESET)
  244.                 prt->state=SCLOSED;
  245.             else 
  246.                 if((uint32)longswap(p->t.ack)!=(prt->out.nxt+1)) {
  247.                     if(p->t.flags&TFIN) {    /* got FIN, no ACK for mine */
  248.                         prt->in.nxt++;                /* account for FIN byte */
  249.                         prt->tcpout.t.ack=longswap(prt->in.nxt);
  250.                         prt->tcpout.t.flags=TACK;    /* final byte has no FIN flag */
  251.                         prt->out.lasttime=0L;        /* cause last ACK to be sent */
  252.                         prt->state=SCLOSING;
  253.                       } /* end if */
  254.                     else {
  255.                         prt->tcpout.t.ack=longswap(prt->in.nxt);
  256.                         prt->tcpout.t.flags=TACK|TFIN;
  257.                         prt->out.lasttime=0L;
  258.                       } /* end else */
  259.                   } /* end if */
  260.                 else 
  261.                     if(p->t.flags&TFIN) {    /* ACK and FIN */
  262.                         prt->in.nxt++;                /* account for his FIN flag */
  263.                         prt->out.nxt++;                /* account for my FIN */
  264.                         prt->tcpout.t.ack=longswap(prt->in.nxt);
  265.                         prt->tcpout.t.flags=TACK;    /* final byte has no FIN flag */
  266.                         prt->out.lasttime=0L;        /* cause last ACK to be sent */
  267.                         prt->state=STWAIT;        /* we are done */
  268.                       } /* end if */
  269.                     else {                            /* got ACK, no FIN */
  270.                         prt->out.nxt++;                /* account for my FIN byte */
  271.                         prt->tcpout.t.flags=TACK;    /* final pkt has no FIN flag */
  272.                         prt->state=SFW2;
  273.                       } /* end else */
  274.                 break;
  275.  
  276.         case SFW2:                                /* want FIN */
  277.             prt->in.nxt=longswap(p->t.seq)+tlen-hlen;
  278.             if(p->t.flags&TRESET)
  279.                 prt->state=SCLOSED;
  280.             else 
  281.                 if(p->t.flags&TFIN) {        /* we got FIN */
  282.                     prt->in.nxt++;                    /* count his FIN byte */
  283.                     prt->tcpout.t.ack=longswap(prt->in.nxt);
  284.                     prt->out.lasttime=0L;        /* cause last ACK to be sent */
  285.                     prt->state=STWAIT;
  286.                   } /* end if */
  287.             break;
  288.  
  289.         case SCLOSING:                        /* want ACK of FIN */
  290.             if(p->t.flags&TRESET)
  291.                 prt->state=SCLOSED;
  292.             else 
  293.                 if(!ackcheck(prt,p,pnum)) {
  294.                     prt->out.nxt++;                /* account for my FIN byte */
  295.                     prt->state=STWAIT;        /* time-wait state next */
  296.                   } /* end if */
  297.             break;
  298.  
  299.         case STWAIT:                        /* ack FIN again? */
  300.             if(p->t.flags&TRESET)
  301.                 prt->state=SCLOSED;
  302.             if(p->t.flags&TFIN)             /* only if he wants it */
  303.                 prt->out.lasttime=0L;
  304.             if(prt->out.lasttime && (prt->out.lasttime+WAITTIME<n_clicks()))
  305.                 prt->state=SCLOSED;
  306.             break;            
  307.  
  308.         case SCLOSED:
  309.             prt->in.port=prt->out.port=0;
  310.             break;
  311.  
  312.         default:
  313.             netposterr(403);            /* unknown tcp state */
  314.             break;
  315.       } /* end switch */
  316.     return(0);
  317. }   /* end tcpdo() */
  318.  
  319. /**********************************************************************/
  320. /*  checkmss
  321. *  Look at incoming SYN,ACK packet and check for the options field
  322. *  containing a TCP Maximum segment size option.  If it has one,
  323. *  then set the port's internal value to make sure that it never
  324. *  exceeds that segment size.
  325. */
  326. static void checkmss(struct port *prt,TCPKT *p,int hlen)
  327. {
  328.     unsigned int i;
  329. /*
  330. *  check header for maximum segment size option
  331. */
  332.     if(hlen>20 && p->x.options[0]==2 && p->x.options[1]==4) {
  333.         movebytes((char *)&i,(char *)&p->x.options[2],2);    /* swapped value of maxseg */
  334.         i=intswap(i);
  335.         if(i<(unsigned int)(prt->sendsize))    /* we have our own limits too */
  336.             prt->sendsize=i;
  337.       } /* end if */
  338. }   /* end checkmss() */
  339.  
  340. /**********************************************************************/
  341. /* tcpreset
  342. *  Send a reset packet back to sender
  343. *  Use the packet which just came in as a template to return to
  344. *  sender.  Fill in all of the fields necessary and dlayersend it back.
  345. */
  346. static int tcpreset(TCPKT *t)
  347. {
  348.     uint tport;
  349.     struct pseudotcp xxx;
  350.  
  351.     if(t->t.flags&TRESET)        /* don't reset a reset */
  352.         return(1);
  353. /*
  354. *  swap TCP layer portions for sending back
  355. */
  356.     if(t->t.flags&TACK) {
  357.         t->t.seq=t->t.ack;        /* ack becomes next seq # */
  358.         t->t.ack=0L;                /* ack # is 0 */
  359.         t->t.flags=TRESET;
  360.       } /* end if */
  361.     else {
  362.         t->t.seq=0L;
  363.         t->t.ack=longswap(longswap(t->t.seq)+t->i.tlen-sizeof(IPLAYER));
  364.         t->t.flags=TRESET|TACK;
  365.       } /* end else */
  366.     tport=t->t.source;              /* swap port #'s */
  367.     t->t.source=t->t.dest;
  368.     t->t.dest=tport;
  369.     t->t.hlen=20<<2;                /* header len */
  370.     t->t.window=0;
  371. /*
  372. *  create pseudo header for checksum
  373. */
  374.     xxx.z=0;
  375.     xxx.proto=t->i.protocol;
  376.     xxx.tcplen=intswap(20);
  377.     movebytes(xxx.source,t->i.ipsource,4);
  378.     movebytes(xxx.dest,t->i.ipdest,4);
  379.     t->t.check=0;    
  380.     t->t.check=tcpcheck((char *)&xxx,(char *)&t->t,sizeof(struct tcph));
  381. /*
  382. *  IP and data link layers
  383. */    
  384.     movebytes(t->i.ipdest,t->i.ipsource,4);  /* machine it came from */
  385.     movebytes(t->i.ipsource,nnipnum,4); 
  386.     t->i.tlen=intswap(sizeof(IPLAYER)+sizeof(TCPLAYER));
  387.     t->i.ident=nnipident++;
  388.     t->i.ttl=30;
  389.     t->i.check=0;
  390.     t->i.check=ipcheck((char *)&t->i,10);
  391.     movebytes(t->d.dest,t->d.me,DADDLEN);    /* data link address */
  392.     movebytes(t->d.me,blankd.me,DADDLEN);    /* my address */
  393.  
  394.     return(dlayersend((DLAYER *)t,sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(TCPLAYER)));
  395. }   /* end tcpreset() */
  396.  
  397. /***************************************************************************/
  398. /*  tcpsend
  399. *     transmits a TCP packet.  
  400. *
  401. *   For IP:
  402. *      sets ident,check,totallen
  403. *   For TCP:
  404. *      sets seq and window from port information,
  405. *        fills in the pseudo header and computes the checksum.
  406. *      Assumes that all fields not filled in here are filled in by the
  407. *      calling proc or were filled in by makeport(). 
  408. *      (see all inits in protinit)
  409. *
  410. */
  411. int tcpsend(struct port *pport,int dlen)
  412. {
  413.     struct port *p;
  414.  
  415.     p=pport;
  416.  
  417.     if(p==NULL) {
  418.         netposterr(404);
  419.         return(-1);
  420.       } /* end if */
  421. /*
  422. *  do IP header first
  423. */
  424.     p->tcpout.i.ident=intswap(nnipident++);
  425.     p->tcpout.i.tlen=intswap(sizeof(struct iph)+sizeof(struct tcph) + dlen);
  426.     p->tcpout.i.check=0;                /* install checksum */
  427.     p->tcpout.i.check=ipcheck((char *)&p->tcpout.i,10);
  428. /*
  429. *  do TCP header
  430. */
  431.     p->tcpout.t.seq=longswap(p->out.nxt);            /* bytes swapped */
  432. /*
  433. *  if the port has some credit limit, use it instead of large
  434. *  window buffer.  Generally demanded by hardware limitations.
  435. */
  436.     if((uint)(p->credit) < (p->in.size))
  437.         p->tcpout.t.window=intswap(p->credit);
  438.     else
  439.         p->tcpout.t.window=intswap(p->in.size);    /* window size */
  440. /*
  441. *  prepare pseudo-header for checksum
  442. */
  443.     p->tcps.tcplen=intswap(dlen+sizeof(TCPLAYER));
  444.     p->tcpout.t.check=0;
  445.     p->tcpout.t.check=tcpcheck((char *)&p->tcps,(char *)&p->tcpout.t,dlen+sizeof(struct tcph));
  446.     p->out.lasttime=n_clicks();
  447.     return(dlayersend((DLAYER *)&p->tcpout,sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(TCPLAYER)+dlen));
  448. }   /* end tcpsend() */
  449.  
  450. /***************************************************************************/
  451. /*  ackcheck
  452. *   take an incoming packet and see if there is an ACK for the outgoing
  453. *   side.  Use that ACK to dequeue outgoing data.
  454. */
  455. static int ackcheck(struct port *p,TCPKT *t,int pnum)
  456. {
  457.     uint32 ak;
  458.     int32 rttl;
  459.     int i;
  460.  
  461.     if((t->t.flags&TRESET) && (t->t.seq==p->tcpout.t.ack)) {
  462.         netposterr(405);
  463.         p->state=SCLOSED;
  464.         netputuev(CONCLASS,CONCLOSE,pnum);
  465.         return(1);
  466.       } /* end if */
  467.     if(!(t->t.flags&TACK))                /* check ACK flag */
  468.         return(1);                             /* if no ACK, no go */
  469.     p->out.size=intswap(t->t.window);    /* allowable transmission size */
  470. /*
  471. *  rmqueue any bytes which have been ACKed, update p->out.nxt to the
  472. *  new next seq number for outgoing.  Update send window.
  473. *
  474. */
  475.     ak=longswap(t->t.ack);            /* other side's ACK */
  476. /*
  477. *  Need to add code to check for wrap-around of sequence space
  478. *  for ak.  ak - p->out.ack may be affected by sequence wraparound.
  479. *  If you have good, efficient code for this, please send it to me.
  480. *
  481. *  If ak is not increasing (above p->out.nxt) then we should assume
  482. *  that it is a duplicate packet or one of those stupid keepalive
  483. *  packets that 4.2 sends out.
  484. */
  485.     if(ak>p->out.nxt) {
  486.         rmqueue(&p->out,(int)(ak - p->out.ack));    /* take off of queue */
  487.         p->out.nxt=ak;
  488.         p->out.ack=ak;
  489. /*
  490. *  Check to see if this acked our most recent transmission.  If so, adjust
  491. *  the RTO value to reflect the newly measured RTT.  This formula reduces
  492. *  the RTO value so that it gradually approaches the most recent round
  493. *  trip measurement.  When a packet is retransmitted, this value is
  494. *  doubled (exponential backoff).
  495. */
  496.         rttl=n_clicks()-p->out.lasttime;
  497.         if(!p->out.contain && rttl<(long)(MAXRTO) && p->rto>=MINRTO) {    /* just now emptied queue */
  498.             i=(int)(rttl);
  499.             i=((p->rto-MINRTO)*3+i+1)>>2;    /* smoothing function */
  500.             p->rto=i+MINRTO;
  501.           } /* end if */
  502.         if(!p->out.contain && p->out.push)    /* if the queue emptied and push was set, clear push */
  503.             p->out.push=0;
  504.         if(p->out.contain>0)
  505.             p->out.lasttime=0L;            /* forces xmit */
  506.         return(0);
  507.       } /* end if */
  508. /* the following line was added by QAK in an attempt to get ftpbin working again. */
  509.     if(p->out.size>0)
  510.         p->out.lasttime=0L;            /* forces xmit */
  511.     return(1);
  512. }   /* end ackcheck() */
  513.  
  514. /***************************************************************************/
  515. /*  estab1986
  516. *   take a packet which has arrived for an established connection and
  517. *   put it where it belongs.
  518. */
  519. static int estab1986(struct port *prt,TCPKT *pkt,int tlen,int hlen)
  520. {
  521.     int dlen;
  522.     uint32 sq,want;
  523.  
  524.     dlen=tlen-hlen;
  525. /*
  526. *  see if we want this packet, or is it a duplicate?
  527. */
  528.     sq=longswap(pkt->t.seq);
  529.     want=prt->in.nxt;
  530.     if(sq!=want) {      /* we may want it, may not */
  531.         if(sq<want&&sq+dlen>=want) {      /* overlap */
  532.             hlen+=(int)(want-sq);        /* offset desired */
  533.             dlen-=(int)(want-sq);        /* skip this much */
  534.           } /* end if */
  535.         else {                                    /* tough it */
  536.             prt->out.lasttime=0L;                /* make the ACK time out */
  537.             return(-1);
  538.           } /* end else */
  539.       } /* end if */
  540.     else 
  541.         if(dlen<=0) {                        /* only an ACK packet */
  542.             checkfin(prt,pkt);                        /* might still have FIN */
  543.             return(0);
  544.           } /* end if */
  545. /*
  546. *  If we have room in the window, update the ACK field values
  547. */
  548.     if((prt->in.size)>=(uint)dlen) {
  549.         prt->in.nxt+=dlen;              /* new ack value */
  550.         prt->in.size-=dlen;                /* new window size */
  551.         prt->out.lasttime=0L;                /* force timeout for ACK */
  552.         enqueue(&prt->in,pkt->x.data+hlen-20,dlen);
  553.         netputuev(CONCLASS,CONDATA,pnum);    /* tell user about it */
  554.         prt->tcpout.t.ack=longswap(prt->in.nxt);
  555.         prt->in.lasttime=n_clicks();
  556.       } /* end if */
  557.     else {                                    /* no room in input buffer */
  558.         prt->out.lasttime=0L;                /* re-ack old sequence value */
  559.       } /* end else */
  560. /* 
  561. *  Check the FIN bit to see if this connection is closing
  562. */
  563.     checkfin(prt,pkt);
  564.     return(0);
  565. }   /* end estab1986() */
  566.  
  567. /***************************************************************************/
  568. /* checkfin
  569. *   Check the FIN bit of an incoming packet to see if the connection
  570. *   should be closing, ACK it if we need to.
  571. *   Half open connections immediately, automatically close.  We do
  572. *   not support them.  As soon as the incoming data is delivered, the
  573. *   connection will close.
  574. */
  575. static void checkfin(struct port *prt,TCPKT *pkt)
  576. {
  577.     if(pkt->t.flags&TFIN) {        /* fin bit found */
  578.         prt->in.nxt++;                /* count the FIN byte */
  579.         prt->state=SCWAIT;        /* close-wait */
  580.         prt->tcpout.t.ack=longswap(prt->in.nxt);    /* set ACK in packet */
  581.         prt->credit=0;
  582.         prt->out.lasttime=0L;        /* cause ACK to be sent */
  583.         netputuev(CONCLASS,CONCLOSE,pnum);
  584. /*
  585. *   At this point, we know that we have received all data that the other
  586. *   side is allowed to send.  Some of that data may still be in the 
  587. *   incoming queue.  As soon as that queue empties, finish off the TCP
  588. *   close sequence.  We are not allowing the user to utilize a half-open
  589. *   connection, but we cannot close before the user has received all of
  590. *   the data from the incoming queue.
  591. */
  592.         if(!prt->in.contain) {                    /* data remaining? */
  593.             prt->tcpout.t.flags=TFIN|TACK;
  594.             tcpsend(prt,0);
  595.             prt->state=SLAST;
  596.           } /* end if */
  597.       } /* end if */
  598. }   /* end checkfin() */
  599.    
  600.