BBN-V6/tcp/psipin.c

#
# include "tcpstru.h"
# include "hdrmasks.h"

# define MAXMSG      1012       /* input/output buffer length */
# define ENDARGS       -1       /* end of Log argument list */

/* ARPANET message types */
# define REGULAR        0
# define NOP            4
# define RFNM           5
# define NOHOST         7


PsipIn(WrkPtr)

struct WorkBlk *WrkPtr;

{
   extern int ShortIn;
   extern int ANLngth;
   extern int Auth;
   extern int Debug;
   extern char TcpIn[TCPINSZ];
   extern char TcpOut[TCPOTSZ];
   extern struct FdsBlk FdsBffer[FDSSIZE];
   extern int WindNum;
   extern int WindDenom;
   extern struct TcpTcb *TcbHd;
   extern int RWindow;
   extern char CmdTcp[CMDTCPSIZE];
   extern int NetFdsW;
   extern int PartWr;
   extern char *OutPtr;
   extern int OutCnt;
   extern long StopSkt[NSTOP];
   extern int StopTcc[NSTOP];

   register struct TcpTcb *XPtr;
   register struct INMask *INPtr;
   register struct TCPMask *TCPPtr;

   struct ANMask *ANPtr;
   struct PortLdr PortHdr;
   int i;
   int INLength;
   int Found;
   struct BSLMask *BSLPtr;
   int Error;
   int PktLength;
   int Cap[2];
   long temp1, temp2;
   long UrgNo;
   int R1, R2;
   char *OctetPtr;
   int BCnt;
   struct WorkBlk *APtr;
   struct PMask1 *ChngPtr;
   struct MUrgent *UrgPtr;
   struct PMask1 *PPtr;
   struct PMask1 *ResetPtr;
   struct PMask1 *RejectPtr;
   int l;
   int *MPtr;
   int DataAmt;
   int AckOk;
   long W;
   int V;
   struct FdsBlk *FdsBffPtr;
   int InPrec;
   int InSec;
   int InTcc;
   int SptOpt;
   int TccOk;
   int Stat;
   int Count;
   char *SPtr;
   char *DPtr;
   int FinOn;
   int SynOn;
   int FinFlag;

   struct
   {  char XHost;
      char XNet;
      int XImp;
    } *SktPtr;


   if (Debug == 1)
   {  printf("PsipIn: entered\n");
    }

   /*
   if (Debug == 4)
   {  Log(6, "s", "PsipIn", ENDARGS);
    }
   */

   /* The ShortIn flag indicates that a segment addressed
   locally is ready in the TcpIn buffer */

   if (ShortIn == 0)
   {  /* read segment from the net */
      Stat = NetIn();

      if (Stat == -1)
      {  return(0);     /* no more incoming segments */
       }

      if (Stat == 0)
      {  /* non-tcp message */
         return(2);        /* move block to end of work queue */
       }
    }

   INPtr = &TcpIn[BSLLNGTH];
   TCPPtr = &TcpIn[(((INPtr -> IVerHdr)&017)*4) + BSLLNGTH];

   if (ShortIn == 1)
   {  /* log it */
      if (Debug == 4)
      {  Log(6, "n", INPtr, ENDARGS);
         Log(6, "t", TCPPtr, ENDARGS);
       }

      ShortIn = 0;
    }

   SynOn = 0;
   FinOn = 0;

   if (((TCPPtr -> TTCPFlags)&SYN) > 0)
   {  SynOn = 1;
    }
   if (((TCPPtr -> TTCPFlags)&FIN) > 0)
   {  FinOn = 1;
    }

   DataAmt = (INPtr -> ISegLength) - (((INPtr -> IVerHdr)&017)*4) -
   ((((TCPPtr ->TTCPFlags)&(0170000)) >> 12)*4);

   PktLength = DataAmt + SynOn + FinOn;

   if (Debug == 1)
   {  /* snap the segment info */
      printf("PsipIn: seg info: L = %d, F = %o, Src = %d\n",
      DataAmt, (TCPPtr -> TTCPFlags)&0777, TCPPtr -> TSrcePort);
    }

   /* check for internet options */

   INLength = (INPtr -> IVerHdr)&017;

   SptOpt = 0;

   i = 0;

   while (i < ((INLength - 5)*4))
   {  switch(INPtr -> IOptions[i])
      {  case OPTSPT:
         {  InSec = (INPtr -> IOptions[i+2])&017;
            InPrec = ((INPtr -> IOptions[i+2]) >> 4)&017;
            InTcc = INPtr -> IOptions[i+3];
            SptOpt = 1;
            i = i + 4;
            break;
          }
         default:
         {  /* unknown option */
            if (INPtr -> IOption[i+1] == 0)
            {  /* will cause hang */
               i = (INLength - 5)*4;  /* get out of loop */
             }
            else
            {  i = i + INPtr -> IOptions[i+1];
             }
          }
       }
    }

   if (Auth == 1)
   {  /* check if incoming segment prohibited by Stop */

      for (i = 0;i < NSTOP; i++)
      {  SktPtr = &StopSkt[i];

         if ((SktPtr -> XHost == INPtr -> ISHstH)&&
         (SktPtr -> XNet == INPtr -> ISrcNet)&&
         (SktPtr -> XImp == INPtr -> ISHstL))
         {  /* ignore the segment */
            printf("PsipIn: Stop %o %o %o\n", INPtr -> ISrcNet,
            INPtr -> ISHstH, INPtr -> ISHstL);

            return(2);    /* move to end of queue */
          }
       }

      if (SptOpt == 0)
      {  return(2);    /* ignore segment */
       }

      /* check TCC */
      for (i = 0; i < NSTOP; i++)
      {  if (StopTcc[i] < 0)
         {  if ((StopTcc[i]&017) == InTcc)
            {  printf("PsipIn: Stop T %d\n", InTcc);
               /* ignore the segment */
               return(2);
             }
          }
       }
    }

   /* find the destination TCB */
   /* first check for non-OPENed connections */
   Found = 0;
   XPtr = TcbHd;

   while((Found == 0)&&(XPtr != 0))
   {  /* match local socket and foreign socket */

      if ((XPtr -> State != OPEN)&&(XPtr -> TMode != 2))
      {  /* check for exact match */
         if ((XPtr -> SrcePort == TCPPtr -> TDestPort)&&
         (XPtr -> DestPort == TCPPtr -> TSrcePort)&&
         (XPtr -> DstNet == INPtr -> ISrcNet)&&
         (XPtr -> DstHstH == INPtr -> ISHstH)&&
         (XPtr -> DstHstL == INPtr -> ISHstL))

         {  /* found the TCB */
            Found = 1;
          }
       }
      if (Found == 0)
      {  XPtr = XPtr -> NxtActTcb;
       }
    }

   if (Found == 0)
   {  /* check TCBs with unspecified local socket parameters */
      XPtr = TcbHd;

      while ((Found == 0)&&(XPtr != 0))
      {  /* match local socket and foreign socket taking into
         account possible unspecified foreign socket parameters */

         if ((XPtr -> State == OPEN)&&(XPtr -> TMode != 2))
         {
            if ((XPtr -> SrcePort == TCPPtr -> TDestPort)&&
            ((XPtr -> DestPort == TCPPtr -> TSrcePort)||(XPtr -> DestPort == 0))&&
            ((XPtr -> DstNet == INPtr -> ISrcNet)||(XPtr -> DstNet == 0))&&
            (((XPtr -> DstHstH == INPtr -> ISHstH)&&
            (XPtr -> DstHstL == INPtr -> ISHstL))||
            ((XPtr -> DstHstH == 0)&&(XPtr -> DstHstL == 0))))

            {  /* found the TCB */
               Found = 1;
             }
          }
         if (Found == 0)
         {  XPtr = XPtr -> NxtActTcb;
          }
       }
    }

   /* check SPT parameters */

   if ((Found == 1)&&(Auth == 1))
   {  /* check for internet SPT option */
      if (SptOpt == 0)
      {  /* no option in segment */
         Found = 0;
       }
      else
      {  /* ignore security if unspecified */
         if (XPtr -> ScMaxIn != -1)
         {  /* validate the security */
            if ((InSec > XPtr -> ScMaxIn)||
            (InSec < XPtr -> ScMinIn))
            {  /* bad security level */
               Found = 0;
             }
          }

         /* validate the receive precedence */
         if ((InPrec > XPtr -> MxRcvPrec)||
         (InPrec < XPtr -> MnRcvPrec))
         {  /* bad precedence level */
            Found = 0;
          }

         /* validate the TCC */
         TccOk = 0;
         i = 0;

         while ((i < XPtr -> TCCCnt)&&(TccOk == 0))
         {  if (XPtr -> TccList[i] == InTcc)
            {  TccOk = 1;
             }
            else
            {  i++;
             }
          }

         if (TccOk == 0)
         {  Found = 0;
          }

       }
    }

   if ((Found == 0)||(XPtr -> State == CLOSED))
   {  /* no matching TCB */
      printf("nm %o %o %o %o\n", TCPPtr -> TSrcePort, INPtr -> ISHstH,
      INPtr -> ISHstL, INPtr -> ISrcNet);

      if (PartWr == 0)      /* forget RST if waiting for netout */
      {  /* if no RST, send ACK, RST */
         if (((TCPPtr -> TTCPFlags)&RST) == 0)
         {  /* immediately send a RST segment */

            /* swap internet fields */
            INPtr -> ISegLength = (((INPtr -> IVerHdr)&017)*4) + TCPLNGTH;
            INPtr -> IINChkSum = 0;
            V = INPtr -> ISrcNet;
            INPtr -> ISrcNet = INPtr -> IDstNet;
            INPtr -> IDstNet = V;
            V = INPtr -> ISHstL;
            INPtr -> ISHstL = INPtr -> IDHstL;
            INPtr -> IDHstL = V;
            V = INPtr -> ISHstH;
            INPtr -> ISHstH = INPtr -> IDHstH;
            INPtr -> IDHstH = V;

            /* swap TCP fields */
            V = TCPPtr -> TSrcePort;
            TCPPtr -> TSrcePort = TCPPtr -> TDestPort;
            TCPPtr -> TDestPort = V;

            W = TCPPtr -> TAckNo;  
            TCPPtr -> TAckNo = TCPPtr -> TSeqNo + PktLength;
            TCPPtr -> TSeqNo = W;

            TCPPtr -> TTCPChkSum = 0;

            TCPPtr -> TTCPFlags = ACK + RST
            + ((TCPPtr -> TTCPFlags)&0170000);

            /* copy segment to TcpOut */

            SPtr = TcpIn;
            DPtr = TcpOut;

            for (i = 0; i < BSLLNGTH + (INPtr -> ISegLength); i++)
            {  *DPtr++ = *SPtr++;
             }

            /* send segment to the net */

            NetOut(0);

          }
       }
      return(2);    /* move work entry */
    }

   /* reset "foreign host not resp" bit */
   XPtr -> Flags =& ~0400;

   XPtr -> SegRecv =+ 1;

   AckOk = 0;

   /* check for ACK */

   if (((TCPPtr -> TTCPFlags)&ACK) > 0)
   {  /* found an ACK bit on */
      /* check for range of Ack */

      R1 = ULCompare(&(XPtr -> LeftSeq), &(TCPPtr -> TAckNo));
      R2 = ULCompare(&(TCPPtr -> TAckNo), &(XPtr -> MaxSend));

      if ((R1 == 2)&&(R2 != 1))
      /* LeftSeq < AckNo <= MaxSend */
      {  /* acceptable */

         AckOk = 1;

         if (R2 == 0)
         /* AckNo = MaxSend */
         {  UnQTcb(XPtr);

            if (XPtr -> State == CLOSING)
            {  /* nothing else to send */
               XPtr -> State = CLOSED;

               /* inform user */

               CmdOut(XPtr, OCHNG, CLOSED, 0);
             }
          }

         XPtr -> DataHd =+ (TCPPtr -> TAckNo) - (XPtr -> LeftSeq);

         /* compensate for SYN, FIN sequence numbers */

         switch(XPtr -> State)
         {  case FINWAIT:
            case CLOSING:
            case CLOSED:
            {  R1 = ULCompare(&(TCPPtr -> TAckNo), &(XPtr -> SndFSN));
               if (R1 == 1)       /* AckNo > SndFSN */
               {  XPtr -> DataHd =- 1;
                }
               break;
             }
            case SYNSENT:
            case SYNRECD:
            {  if (XPtr -> LeftSeq == XPtr -> SndISN)
               {  XPtr -> DataHd =- 1;
                }
               break;
             }
          }

         if (XPtr -> DataHd >= RBUFFSIZE)
         {  XPtr -> DataHd =- RBUFFSIZE;
          }

         XPtr -> LeftSeq = TCPPtr -> TAckNo;

         R1 = ULCompare(&(TCPPtr -> TAckNo), &(XPtr -> SendSeq));

         if (R1 == 1)
         /* AckNo > SendSeq */
         {  XPtr -> SendSeq = TCPPtr -> TAckNo;

            XPtr -> DataNxt = XPtr -> DataHd;
          }

         /* check if send urgent can be turned off */
         R1 = ULCompare(&(XPtr -> LeftSeq), &(XPtr -> SndUrgNo));

         if (R1 != 2)   /* LeftSeq >= SndUrgNo */
         {  /* turn off send urgent flag */
            XPtr -> Flags =& ~01;
          }

         /* schedule work for DataIn in case there is
         more data in the port */

         MakeWrk(0, USERINHP, XPtr, XPtr -> SendPort);

         if (((TCPPtr -> TTCPFlags)&RST) == 0)
         {  /* schedule work for PsipOut in case segmentation
            is being held up because of window or buffer limits */

            MakeWrk(0, NETOUTHP, XPtr, NetFdsW);

            if (XPtr -> State == SYNRECD)
            {  /* go into established state */

               XPtr -> State = ESTAB;

               /* inform user */

               CmdOut(XPtr, OCHNG, ESTAB, 0);

               /* bind receive precedence */
               XPtr -> MxRcvPrec = InPrec;
               XPtr -> MnRcvPrec = InPrec;

             }

            XPtr -> NumRetran = 0;

            if (((XPtr -> Flags)&04) > 0)
            {  /* inform user foreign proc is back */
               PPtr = CmdTcp;
               PPtr -> YOpCode = OPROCR;
               PPtr -> YHandle = XPtr -> ConnHandle;
               write(XPtr -> TCPCmdPort, CmdTcp, 4);

               XPtr -> Flags =& ~04;    /* reset flag */
             }
          }
       }

      else
      {  /* ACK not acceptable */

         /* decide whether to return a RST */

         switch(XPtr -> State)
         {  case OPEN:
            case SYNSENT:
            case SYNRECD:
            case CLOSED:
            {  /* check for RST */

               if (((TCPPtr -> TTCPFlags)&RST) == 0)
               {  /* return a RST */

                  XPtr -> SeqNo = TCPPtr -> TAckNo;
                  XPtr -> AckNo = TCPPtr -> TSeqNo + PktLength;
                  XPtr -> TCPFlags =| ACK + RST;

                  MakeWrk(0, NETOUTHP, XPtr, NetFdsW);
                }
             }
          }
       }
    }


   /* check for RST */
   /* ACK ignored since I could lose a "courtesy RST" this way */

   if (((TCPPtr -> TTCPFlags)&RST) > 0)
   {  /* RST bit is on */

      switch (XPtr -> State)
      {  case OPEN:
         case CLOSED:
         {  break;    /* ignore the RST */
          }
         case SYNSENT:
         {  /* foreign TCP rejecting */
            /* send only one message to user */

            if (((XPtr -> Flags)&0100) == 0)
            {  /* inform user */
               RejectPtr = CmdTcp;
               RejectPtr -> YOpCode = OREJECT;
               RejectPtr -> YHandle = XPtr -> ConnHandle;
               write(XPtr -> TCPCmdPort, CmdTcp, 4);

               XPtr -> Flags =| 0100;    /* set flag */

             }
            XPtr -> LeftSeq = XPtr -> SndISN;
            XPtr -> SendSeq = XPtr -> SndISN;
            XPtr -> MaxSend = XPtr -> SndISN;

            /* put TCB on retransmission queue */
            QTcb(XPtr);
            break;
          }
         case SYNRECD:
         {  XPtr -> State = OPEN;

            /* restore unspecified foreign socket parameters */

            XPtr -> DstNet = XPtr -> OpnNet;
            XPtr -> DstHstH = XPtr -> OpnHstH;
            XPtr -> DstHstL = XPtr -> OpnHstL;
            XPtr -> DestPort = XPtr -> OpnPort;

            XPtr -> LeftSeq = XPtr -> SndISN;
            XPtr -> SendSeq = XPtr -> SndISN;
            XPtr -> MaxSend = XPtr -> SndISN;

            XPtr -> DataHd = 0;
            XPtr -> DataTl = 0;
            XPtr -> DataNxt = 0;

            /* restore precedence, TCC parameters */

            break;
          }
         default:
         {  /* all other connection states */
            /* close the connection and inform user */

            XPtr -> State = CLOSED;

            XPtr -> Flags =| 040;    /* send no more segments */

            UnQTcb(XPtr);

            /* send "connection reset" message to user */

            ResetPtr = CmdTcp;
            ResetPtr -> YOpCode = ORESET;
            ResetPtr -> YHandle = XPtr -> ConnHandle;
            write(XPtr -> TCPCmdPort, CmdTcp, 4);

            /* send state change message */

            CmdOut(XPtr, OCHNG, CLOSED, 0);

            break;
          }
       }
      return(2);    /* move work block */
    }

   /* update the send window size */
   XPtr -> SndWindow = TCPPtr -> TWindow;

   if (XPtr -> SndWindow > 0)
   {  /* reset flag which ensures that ACKs into
      a zero window do not send data unless retransmitting */

      XPtr -> Flags =& ~XRTNDATA;
    }

   switch (XPtr -> State)
   {  case OPEN:
      {
         if (SynOn > 0)
         {  /* segment contains SYN bit */
            /* fill in unspecified foreign socket parameters */
            XPtr -> DestPort = TCPPtr -> TSrcePort;
            XPtr -> DstNet = INPtr -> ISrcNet;
            XPtr -> DstHstH = INPtr -> ISHstH;
            XPtr -> DstHstL = INPtr -> ISHstL;

            if (Auth == 1)
            {  /* check if send precedence level is high enough */
               if (InPrec > XPtr -> SndPrec)
               {  /* check if allowable to boost send precedence */
                  if (InPrec <= XPtr -> ATPrec)
                  {  /* boost to match incoming */
                     XPtr -> SndPrec = InPrec;

                     /* inform user of send precedence change */

                     PPtr = CmdTcp;
                     PPtr -> YOpCode = OPRECCHNG;
                     PPtr -> YHandle = XPtr -> ConnHandle;
                     PPtr -> YMisc = XPtr -> SndPrec;

                     write(XPtr -> TCPCmdPort, CmdTcp, 6);
                   }
                  else
                  {  /* check if can boost to highest possible */
                     if (XPtr -> SndPrec < XPtr -> ATPrec)
                     {  /* boost up to auth table value */
                        XPtr -> SndPrec = XPtr -> ATPrec;

                        /* inform user of send precedence change */

                        PPtr = CmdTcp;
                        PPtr -> YOpCode = OPRECCHNG;
                        PPtr -> YHandle = XPtr -> ConnHandle;
                        PPtr -> YMisc = XPtr -> SndPrec;

                        write(XPtr -> TCPCmdPort, CmdTcp, 6);
                      }
                   }
                }
               /* bind the security for unspecified connection */
               if (XPtr -> ScMaxOut == -1)
               {  XPtr -> ScMaxOut = InSec;
                  XPtr -> ScMinOut = InSec;
                }

               /* bind the TCC */
               XPtr -> TCCCnt = 1;
               XPtr -> TccList[0] = InTcc;
             }

            /* begin 3-way handshake */
            /* assumes no data with SYN */

            XPtr -> TCPFlags =| ACK;  /* set ACK bit */
            XPtr -> AckNo = (TCPPtr -> TSeqNo) +1;
            XPtr -> RcvISN = TCPPtr -> TSeqNo;

            /* create some work for PsipOut */
            MakeWrk(0, NETOUTHP, XPtr, NetFdsW);

            /* go into SYN-RECD state */
            XPtr -> State = SYNRECD;

            /* notify user in case he is a server
            and needs to fork */

            CmdOut(XPtr, OCHNG, SYNRECD, 0);
          }
         return(2);    /* move work entry */
       }
      case SYNRECD:
      case CLOSED:      /* since ACK can cause CLOSED state */
      {
         return(2);    /* move work entry */
       }
      case SYNSENT:
      {
         if (SynOn > 0)
         {  /* found SYN = 1 */
            XPtr -> AckNo = (TCPPtr -> TSeqNo) + 1;
            XPtr -> TCPFlags =| ACK;   /* set ACK = 1 */

            if (Auth == 1)
            {  /* check if send precedence level is high enough */
               if (InPrec > XPtr -> SndPrec)
               {  /* check if allowable to boost send precedence */
                  if (InPrec <= XPtr -> ATPrec)
                  {  /* boost to match incoming */
                     XPtr -> SndPrec = InPrec;

                     /* inform user of send precedence change */

                     PPtr = CmdTcp;
                     PPtr -> YOpCode = OPRECCHNG;
                     PPtr -> YHandle = XPtr -> ConnHandle;
                     PPtr -> YMisc = XPtr -> SndPrec;

                     write(XPtr -> TCPCmdPort, CmdTcp, 6);
                   }
                  else
                  {  /* check if can boost to highest possible */
                     if (XPtr -> SndPrec < XPtr -> ATPrec)
                     {  /* boost up to auth table value */
                        XPtr -> SndPrec = XPtr -> ATPrec;

                        /* inform user of send precedence change */

                        PPtr = CmdTcp;
                        PPtr -> YOpCode = OPRECCHNG;
                        PPtr -> YHandle = XPtr -> ConnHandle;
                        PPtr -> YMisc = XPtr -> SndPrec;

                        write(XPtr -> TCPCmdPort, CmdTcp, 6);
                      }
                   }
                }
             }

            R1 = ULCompare(&(XPtr -> LeftSeq),&(XPtr -> SndISN));

            /* check for ACK */
            if ((AckOk == 1)||(R1 == 1))
            /* R1 = 1 => LeftSeq > SndISN */
            /* implies SYN already acked */
            {  XPtr -> State = ESTAB;

               /* send change notice to user */

               CmdOut(XPtr, OCHNG, ESTAB, 0);

               /* bind receive precedence */
               XPtr -> MxRcvPrec = InPrec;
               XPtr -> MnRcvPrec = InPrec;

             }
            else
            {  XPtr -> State = SYNRECD;
             }

            /* send ACK segment */
            /* make some work for PsipOut */

            MakeWrk(0, NETOUTHP, XPtr, NetFdsW);

          }
         return(2);    /* move work entry */
       }



      case ESTAB:
      case FINWAIT:
      case CLOSEWAIT:
      case CLOSING:

      {
         /* check for urgent flag */
         if ((XPtr -> State == ESTAB)||(XPtr -> State == FINWAIT))
         {  if (((TCPPtr -> TTCPFlags)&URG) > 0)
            {  /* URG = 1 */
               /* calculate actual sequence number */
               /* the following craziness reqd because
               of sign extension */

               z = &UrgNo;
               z -> bb[0] = 0;
               z -> bb[1] = TCPPtr -> TUrgentPtr;

               UrgNo =+ TCPPtr -> TSeqNo;

               /* check to see if user should be notified */
               /* fix this: segments may arrive out of order */

               if ((((XPtr -> Flags)&02) == 0)||(XPtr -> RcvUrgNo != UrgNo))
               {  /* send urgent message to user */
                  XPtr -> RcvUrgNo = UrgNo;
                  XPtr -> Flags =| 02;

                  UrgPtr = CmdTcp;
                  UrgPtr -> UOpCode = OURGENT;
                  UrgPtr -> UHandle = XPtr -> ConnHandle;
                  UrgPtr -> UByteNo = UrgNo - (XPtr -> RcvISN) - 1 /* for SYN */;
                  write(XPtr -> TCPCmdPort, CmdTcp, 8);
                }
             }
          }

         if (PktLength > 0)
         {  /* data arrived (or data plus SYN or FIN) */

            /* get capacity of user receive port */

            capac(XPtr -> RecvPort, Cap, 4);

            /* calculate new receive window */
            XPtr -> Window = ((Cap[1]*WindNum)/WindDenom) - HDRLNGTH;

            if (XPtr -> Window > RWindow)
            {  /* reset to max size allowed */
               XPtr -> Window = RWindow;
             }

            if (XPtr -> Window < 0)
            {  XPtr -> Window = 0;
             }

            /* check if next in sequence */
            /* check PKT-SEQUENCE */
            temp1 = (TCPPtr -> TSeqNo) + (PktLength-1);
            temp2 = (XPtr -> AckNo) + (XPtr -> Window);

            R1 = ULCompare(&(XPtr -> AckNo), &temp1);
            R2 = ULCompare(&temp1, &temp2);

            if ((R1 != 1)&&(R2 == 2))
            /* AckNo <= SeqNo + PktLength-1 < AckNo + Window */

            {  /* acceptable segment */
               R1 = ULCompare(&(TCPPtr -> TSeqNo), &(XPtr -> AckNo));

               if (R1 == 1)    /* SeqNo > AckNo */

               {  /* not in order */
                  /* for now discard segment! */
                  XPtr -> BusyRecv =+ 1;
                  printf("out of order\n");
                }
               else
               {
                  /* make ptr to first data octet */

                  OctetPtr = &TcpIn[(((INPtr -> IVerHdr)&017)*4) + BSLLNGTH +
                  ((((TCPPtr -> TTCPFlags)&0170000) >> 12)*4)];

                  /* determine number of next in sequence data bytes */

		  /* the SynOn compensation is there to fix a bug
		  which caused a loss of the first byte when a
		  retransmission of SYN + Data was received in the
		  ESTAB state.  */

		  if (SynOn == 1)
		  { printf("PsipIn: ESTAB and SYN + %d bytes\n", DataAmt);
		   }

		  BCnt = DataAmt + SynOn
		  - ((XPtr -> AckNo) - (TCPPtr -> TSeqNo));

                  if (Cap[1] < HDRLNGTH + BCnt)
                  {  /* no space in receive port */
                     /* for now, discard segment */
                     printf("no recv space\n");
                   }
                  else
                  {  /* move ptr to next octet in sequence */
                     OctetPtr =+ DataAmt - BCnt;

                     if (BCnt != 0)
                     {  write(XPtr -> RecvPort, OctetPtr, BCnt);

                        /* update window */
                        XPtr -> Window =- BCnt + HDRLNGTH;
                        if (XPtr -> Window < 0)
                        {  XPtr -> Window = 0;
                         }
                      }

                     XPtr -> AckNo = (TCPPtr -> TSeqNo) + PktLength;

                     /* data sent to user, check for FIN */

                     if (FinOn > 0)
                     {  /* FIN bit is on */

                        /* close port to indicate EOF */
                        /* close(XPtr -> RecvPort); */

                        if (XPtr -> State == ESTAB)
                        {  XPtr -> State = CLOSEWAIT;

                           /* notify user of receipt of FIN */

                           CmdOut(XPtr, OCHNG, CLOSEWAIT, 0);
                         }

                        else if (XPtr -> State == FINWAIT)
                        {  /* check if all data and controls
                           have been acked */

                           if (XPtr -> LeftSeq == XPtr -> MaxSend)
                           {  /* everything acknowledged */
                              XPtr -> State = CLOSED;

                              /* send user connection state change */

                              CmdOut(XPtr, OCHNG, CLOSED, 0);
                            }
                           else
                           {  XPtr -> State = CLOSING;
                            }
                         }
                      }
                   }
                }
             }
            /* send back an ACK */
            XPtr -> TCPFlags =| ACK;    /* set the ACK bit */

            /* make some work for PsipOut */

            MakeWrk(0, NETOUTHP, XPtr, NetFdsW);

          }
         return(2);    /* move work entry */
       }

      default:
      {
         printf("PsipIn: bad TCB state: %d\n", XPtr -> State);
         return(0);
       }

    }
 }


/* Subroutine for handling traffic from the net */

NetIn()

{
   extern int ANLngth;
   extern Debug;
   extern int NetFdsR;
   extern char TcpOut[TCPOTSZ];
   extern char TcpIn[TCPINSZ];
   extern int DoChkSum;
   extern struct TcpTcb *TcbHd;
   extern int LocNet;
   extern int LocHost;
   extern int LocImp;
   extern int PartWr;

   register char *SPtr, *DPtr;

   int BCnt;
   struct ANMask1 *ANPtr1;
   struct ANMask2 *ANPtr2;
   struct BSLMask *BSLPtr;
   struct INLMask *INPtr;
   struct TCPMask *TCPPtr;
   struct TcpTcb *XPtr;
   int ILength;
   int DLength;
   int TLength;
   char *BPtr;
   int Chk;
   int Error;
   int PHdr[2];
   int BHost;
   int BImp;
   int MType;
   int i;
   int SType;

   BCnt = read(NetFdsR, &TcpIn[BSLLNGTH - ANLngth*2 - 2], MAXMSG);

   if (BCnt == -1)
   {  /* read error */
      printf("read error\n");
      return(0);
    }

   if (BCnt == 0)
   {  return(-1);
    }
   else
   {  /* check for message type */
      ANPtr1 = &TcpIn[BSLLNGTH - ANLngth*2 - 2];
      ANPtr2 = ANPtr1;

      if (ANLngth == 2)
      {  MType = ANPtr1 -> Type1;
         SType = ANPtr1 -> SbType1;
       }
      else
      {  MType = ANPtr2 -> Type2;
         SType = ANPtr2 -> SbType2;
       }

      switch(MType)
      {  case RFNM:
         {  /* RFNM arrived */
            return(0);
          }

         case REGULAR:
         {  /* a regular message arrived */
            BSLPtr = TcpIn;

            INPtr = &TcpIn[BSLLNGTH];

            /* remember, the bytes are arriving swapped */
            ILength = ((INPtr -> ITypeService)&017)*4;

            if (ILength < 20)
            {  printf("PsipIn: IN ldr too short\n");
               return(0);
             }

            /* swap the internet bytes */
            Swap(INPtr, ILength);

            /* check if this is version 4 internet leader */

            if ((((INPtr -> IVerHdr) >> 4)&017)  != INVERNO)
            {  /* printf("PsipIn: bad IN version\n"); */
               return(0);
             }

            if (DoChkSum == 1)
            {  /* check the internet checksum */

               if (ChkSum(INPtr, ILength/2, 0, 0) != -1)
               {  /* bad internet checksum -
                  drop incoming segment on the floor */

                  printf("bad IN checksum\n");
                  return(0);
                }
             }

            /* check if this host is the destination */

            if ((INPtr -> IDstNet != LocNet)||
            (INPtr -> IDHstH != LocHost)||
	    (INPtr -> IDHstL != LocImp))
            {  /* segment is destined for some other host */

               if (PartWr == 1)
               {  /* discard it */
                  return(0);
                }

               /* copy to TcpOut */

               DPtr = &TcpOut[BSLLNGTH];
               SPtr = &TcpIn[BSLLNGTH];
               BCnt = INPtr -> ISegLength;

               for (i = 0; i < BCnt; i++)
               {  *DPtr++ = *SPtr++;
                }

               NetOut(1);  /* send back out to net */

               return(0);
             }

            /* check for TCP protocol */

            if (INPtr -> IProtocol != TCPVERNO)
            {  printf("Psipin: bad TCP version\n");
               return(0);
             }

            /* get the length of the tcp header */
            /* the 12th byte is the TCP offset byte */

            TCPPtr = &TcpIn[BSLLNGTH + ILength];

            TLength = ((TcpIn[BSLLNGTH + ILength + 12]) >> 4)*4;

            if (TLength < TCPLNGTH)
            {  printf("PsipIn: TCP ldr too short\n");
               return(0);
             }

            DLength = INPtr -> ISegLength - ILength - TLength;

            /* swap the TCP header bytes */

            Swap(TCPPtr, TLength);

            if ((Debug == 1)||(Debug == 3)||(Debug == 4))
            {
               Error = Log(2, "n", INPtr, ENDARGS);
               Error = Log(2, "t", TCPPtr, ENDARGS);
             }

            if (DoChkSum == 1)
            {  /* check the TCP checksum */

               BPtr = &TcpIn[BSLLNGTH + 12];

               Chk = ChkSum(BPtr, 4, 0, 0);
               Chk = ChkSum(TCPPtr, TLength/2, Chk, 0);

               /* don't forget the protocol and length additions */
               BPtr = &PHdr[0];
               PHdr[0] = (INPtr -> ISegLength) - ILength;
               PHdr[1] = INPtr -> IProtocol;

               Chk = ChkSum(BPtr, 2, Chk, 0);

               BPtr = &TcpIn[BSLLNGTH + ILength + TLength];

               /* check for odd byte count */
               if ((DLength&01) > 0)
               {
                  /* need to pad with zero byte */
                  TcpIn[BSLLNGTH + ILength + TLength + DLength] = 0;
                  DLength =+ 1;
                }
               Chk = ChkSum(BPtr, DLength/2, Chk, 1 /* swap */);

               if (Chk != -1)
               {  /* TCP checksum error -
                  drop segment on the floor */
                  printf("bad TCP checksum\n");
                  return(0);
                }
             }
            return(1);
          }

         case NOP:
         {  /* NOP message arrived */
            return(0);
          }

         case NOHOST:
         {  /* host not responding */

            if (ANLngth == 2)
            {  BHost = (ANPtr1 -> Host1) >> 6;
               BImp = (ANPtr1 -> Host1)&077;
             }
            else
            {  BHost = ANPtr2 -> Host2;
               BImp = ANPtr2 -> Imp2;
             }

            /* inform all users talking to this host */
            /* search TCBs for this foreign host */

            XPtr = TcbHd;

            while(XPtr != 0)
            {  if ((XPtr -> DstHstH == BHost)&&
               (XPtr -> DstHstL == BImp)&&
               (XPtr -> DstNet == LocNet))
               {  /* found one */
                  /* inform user only once */
                  if (((XPtr -> Flags)&0400) == 0)
                  {  CmdOut(XPtr, ONETMSG, 1 /* host not resp */, 0);
                     XPtr -> Flags =| 0400;  /* set flag */
                   }
                }
               XPtr = XPtr -> NxtActTcb;
             }

            return(0);
          }

         default:
         {  printf("Type %d message, Subtype %d\n", MType, SType);
          }

       }
    }
 }



/* Subroutine for swapping bytes to get them out in
the right order */

Swap(P, BCnt)

char *P;
int BCnt;

{
   struct aa
   {  char Byte[MAXMSG];
    };

   register struct aa *Ptr;
   register int i;
   register char T;

   Ptr = P;

   for (i = 0; i < BCnt;)
   {
      T = Ptr -> Byte[i];
      Ptr -> Byte[i] = Ptr -> Byte[i+1];
      Ptr -> Byte[i+1] = T;
      i = i + 2;
    }
 }



/* Subroutine which calculates the checksum */

ChkSum(Ptr, WCnt, OldChk, SwapFlag)

int *Ptr;
int WCnt;
int OldChk;
int SwapFlag;

{
   int i;
   int CheckSum;
   int C;
   char Temp;
   int NxtWd;

   struct
   {  char Byte[2];
    } *BPtr;


   BPtr = &NxtWd;

   CheckSum = OldChk;

   for (i = 0; i < WCnt; i++)
   {  NxtWd = *Ptr;

      if (SwapFlag == 1)
      {  /* the bytes need to be swapped first */
         Temp = BPtr -> Byte[0];
         BPtr -> Byte[0] = BPtr -> Byte[1];
         BPtr -> Byte[1] = Temp;
       }

      /* determine the carry bit */
      C = 0;

      if ((CheckSum < 0)&&(NxtWd < 0))
      {  C = 1;
       }
      else if (((CheckSum^(NxtWd)) < 0)&&((CheckSum + NxtWd) >= 0))
      {  C = 1;
       }

      CheckSum =+ (NxtWd) + C;
      Ptr++;
    }
   return(CheckSum);
 }