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