]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c
MdeModulePkg: Delete Tcp4Dxe in MdeModulePkg.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / Tcp4Input.c
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c
deleted file mode 100644 (file)
index f48efda..0000000
+++ /dev/null
@@ -1,1497 +0,0 @@
-/** @file\r
-  TCP input process routines.\r
-\r
-Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php<BR>\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-\r
-#include "Tcp4Main.h"\r
-\r
-\r
-/**\r
-  Check whether the sequence number of the incoming segment is acceptable.\r
-\r
-  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
-  @param  Seg      Pointer to the incoming segment.\r
-\r
-  @retval 1       The sequence number is acceptable.\r
-  @retval 0       The sequence number is not acceptable.\r
-\r
-**/\r
-INTN\r
-TcpSeqAcceptable (\r
-  IN TCP_CB  *Tcb,\r
-  IN TCP_SEG *Seg\r
-  )\r
-{\r
-  return (TCP_SEQ_LEQ (Tcb->RcvNxt, Seg->End) &&\r
-          TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2 + Tcb->RcvWnd));\r
-}\r
-\r
-\r
-/**\r
-  NewReno fast recovery, RFC3782.\r
-\r
-  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
-  @param  Seg      Segment that triggers the fast recovery.\r
-\r
-**/\r
-VOID\r
-TcpFastRecover (\r
-  IN OUT TCP_CB  *Tcb,\r
-  IN     TCP_SEG *Seg\r
-  )\r
-{\r
-  UINT32  FlightSize;\r
-  UINT32  Acked;\r
-\r
-  //\r
-  // Step 1: Three duplicate ACKs and not in fast recovery\r
-  //\r
-  if (Tcb->CongestState != TCP_CONGEST_RECOVER) {\r
-\r
-    //\r
-    // Step 1A: Invoking fast retransmission.\r
-    //\r
-    FlightSize        = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
-\r
-    Tcb->Ssthresh     = MAX (FlightSize >> 1, (UINT32) (2 * Tcb->SndMss));\r
-    Tcb->Recover      = Tcb->SndNxt;\r
-\r
-    Tcb->CongestState = TCP_CONGEST_RECOVER;\r
-    TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
-\r
-    //\r
-    // Step 2: Entering fast retransmission\r
-    //\r
-    TcpRetransmit (Tcb, Tcb->SndUna);\r
-    Tcb->CWnd = Tcb->Ssthresh + 3 * Tcb->SndMss;\r
-\r
-    DEBUG ((EFI_D_NET, "TcpFastRecover: enter fast retransmission"\r
-      " for TCB %p, recover point is %d\n", Tcb, Tcb->Recover));\r
-    return;\r
-  }\r
-\r
-  //\r
-  // During fast recovery, execute Step 3, 4, 5 of RFC3782\r
-  //\r
-  if (Seg->Ack == Tcb->SndUna) {\r
-\r
-    //\r
-    // Step 3: Fast Recovery,\r
-    // If this is a duplicated ACK, increse Cwnd by SMSS.\r
-    //\r
-\r
-    // Step 4 is skipped here only to be executed later\r
-    // by TcpToSendData\r
-    //\r
-    Tcb->CWnd += Tcb->SndMss;\r
-    DEBUG ((EFI_D_NET, "TcpFastRecover: received another"\r
-      " duplicated ACK (%d) for TCB %p\n", Seg->Ack, Tcb));\r
-\r
-  } else {\r
-\r
-    //\r
-    // New data is ACKed, check whether it is a\r
-    // full ACK or partial ACK\r
-    //\r
-    if (TCP_SEQ_GEQ (Seg->Ack, Tcb->Recover)) {\r
-\r
-      //\r
-      // Step 5 - Full ACK:\r
-      // deflate the congestion window, and exit fast recovery\r
-      //\r
-      FlightSize        = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
-\r
-      Tcb->CWnd         = MIN (Tcb->Ssthresh, FlightSize + Tcb->SndMss);\r
-\r
-      Tcb->CongestState = TCP_CONGEST_OPEN;\r
-      DEBUG ((EFI_D_NET, "TcpFastRecover: received a full ACK(%d)"\r
-        " for TCB %p, exit fast recovery\n", Seg->Ack, Tcb));\r
-\r
-    } else {\r
-\r
-      //\r
-      // Step 5 - Partial ACK:\r
-      // fast retransmit the first unacknowledge field\r
-      // , then deflate the CWnd\r
-      //\r
-      TcpRetransmit (Tcb, Seg->Ack);\r
-      Acked = TCP_SUB_SEQ (Seg->Ack, Tcb->SndUna);\r
-\r
-      //\r
-      // Deflate the CWnd by the amount of new data\r
-      // ACKed by SEG.ACK. If more than one SMSS data\r
-      // is ACKed, add back SMSS byte to CWnd after\r
-      //\r
-      if (Acked >= Tcb->SndMss) {\r
-        Acked -= Tcb->SndMss;\r
-\r
-      }\r
-\r
-      Tcb->CWnd -= Acked;\r
-\r
-      DEBUG ((EFI_D_NET, "TcpFastRecover: received a partial"\r
-        " ACK(%d) for TCB %p\n", Seg->Ack, Tcb));\r
-\r
-    }\r
-  }\r
-}\r
-\r
-\r
-/**\r
-  NewReno fast loss recovery, RFC3792.\r
-\r
-  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
-  @param  Seg      Segment that triggers the fast loss recovery.\r
-\r
-**/\r
-VOID\r
-TcpFastLossRecover (\r
-  IN OUT TCP_CB  *Tcb,\r
-  IN     TCP_SEG *Seg\r
-  )\r
-{\r
-  if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
-\r
-    //\r
-    // New data is ACKed, check whether it is a\r
-    // full ACK or partial ACK\r
-    //\r
-    if (TCP_SEQ_GEQ (Seg->Ack, Tcb->LossRecover)) {\r
-\r
-      //\r
-      // Full ACK: exit the loss recovery.\r
-      //\r
-      Tcb->LossTimes    = 0;\r
-      Tcb->CongestState = TCP_CONGEST_OPEN;\r
-\r
-      DEBUG ((EFI_D_NET, "TcpFastLossRecover: received a "\r
-        "full ACK(%d) for TCB %p\n", Seg->Ack, Tcb));\r
-\r
-    } else {\r
-\r
-      //\r
-      // Partial ACK:\r
-      // fast retransmit the first unacknowledge field.\r
-      //\r
-      TcpRetransmit (Tcb, Seg->Ack);\r
-      DEBUG ((EFI_D_NET, "TcpFastLossRecover: received a "\r
-        "partial ACK(%d) for TCB %p\n", Seg->Ack, Tcb));\r
-    }\r
-  }\r
-}\r
-\r
-\r
-/**\r
-  Compute the RTT as specified in RFC2988.\r
-\r
-  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
-  @param  Measure  Currently measured RTT in heart beats.\r
-\r
-**/\r
-VOID\r
-TcpComputeRtt (\r
-  IN OUT TCP_CB *Tcb,\r
-  IN     UINT32 Measure\r
-  )\r
-{\r
-  INT32 Var;\r
-\r
-  //\r
-  // Step 2.3: Compute the RTO for subsequent RTT measurement.\r
-  //\r
-  if (Tcb->SRtt != 0) {\r
-\r
-    Var = Tcb->SRtt - (Measure << TCP_RTT_SHIFT);\r
-\r
-    if (Var < 0) {\r
-      Var = -Var;\r
-    }\r
-\r
-    Tcb->RttVar = (3 * Tcb->RttVar + Var) >> 2;\r
-    Tcb->SRtt   = 7 * (Tcb->SRtt >> 3) + Measure;\r
-\r
-  } else {\r
-    //\r
-    // Step 2.2: compute the first RTT measure\r
-    //\r
-    Tcb->SRtt   = Measure << TCP_RTT_SHIFT;\r
-    Tcb->RttVar = Measure << (TCP_RTT_SHIFT - 1);\r
-  }\r
-\r
-  Tcb->Rto = (Tcb->SRtt + MAX (8, 4 * Tcb->RttVar)) >> TCP_RTT_SHIFT;\r
-\r
-  //\r
-  // Step 2.4: Limit the RTO to at least 1 second\r
-  // Step 2.5: Limit the RTO to a maxium value that\r
-  // is at least 60 second\r
-  //\r
-  if (Tcb->Rto < TCP_RTO_MIN) {\r
-    Tcb->Rto = TCP_RTO_MIN;\r
-\r
-  } else if (Tcb->Rto > TCP_RTO_MAX) {\r
-    Tcb->Rto = TCP_RTO_MAX;\r
-\r
-  }\r
-\r
-  DEBUG ((EFI_D_NET, "TcpComputeRtt: new RTT for TCB %p"\r
-    " computed SRTT: %d RTTVAR: %d RTO: %d\n",\r
-    Tcb, Tcb->SRtt, Tcb->RttVar, Tcb->Rto));\r
-\r
-}\r
-\r
-\r
-/**\r
-  Trim the data, SYN and FIN to fit into the window defined by Left and Right.\r
-\r
-  @param  Nbuf     Buffer that contains received TCP segment without IP header.\r
-  @param  Left     The sequence number of the window's left edge.\r
-  @param  Right    The sequence number of the window's right edge.\r
-\r
-**/\r
-VOID\r
-TcpTrimSegment (\r
-  IN NET_BUF   *Nbuf,\r
-  IN TCP_SEQNO Left,\r
-  IN TCP_SEQNO Right\r
-  )\r
-{\r
-  TCP_SEG   *Seg;\r
-  TCP_SEQNO Urg;\r
-  UINT32    Drop;\r
-\r
-  Seg = TCPSEG_NETBUF (Nbuf);\r
-\r
-  //\r
-  // If the segment is completely out of window,\r
-  // truncate every thing, include SYN and FIN.\r
-  //\r
-  if (TCP_SEQ_LEQ (Seg->End, Left) || TCP_SEQ_LEQ (Right, Seg->Seq)) {\r
-\r
-    TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);\r
-    TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);\r
-\r
-    Seg->Seq = Seg->End;\r
-    NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_HEAD);\r
-    return;\r
-  }\r
-\r
-  //\r
-  // Adjust the buffer header\r
-  //\r
-  if (TCP_SEQ_LT (Seg->Seq, Left)) {\r
-\r
-    Drop      = TCP_SUB_SEQ (Left, Seg->Seq);\r
-    Urg       = Seg->Seq + Seg->Urg;\r
-    Seg->Seq  = Left;\r
-\r
-    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
-      TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);\r
-      Drop--;\r
-    }\r
-\r
-    //\r
-    // Adjust the urgent point\r
-    //\r
-    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG)) {\r
-\r
-      if (TCP_SEQ_LT (Urg, Seg->Seq)) {\r
-\r
-        TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);\r
-      } else {\r
-        Seg->Urg = (UINT16) TCP_SUB_SEQ (Urg, Seg->Seq);\r
-      }\r
-    }\r
-\r
-    if (Drop != 0) {\r
-      NetbufTrim (Nbuf, Drop, NET_BUF_HEAD);\r
-    }\r
-  }\r
-\r
-  //\r
-  // Adjust the buffer tail\r
-  //\r
-  if (TCP_SEQ_GT (Seg->End, Right)) {\r
-\r
-    Drop      = TCP_SUB_SEQ (Seg->End, Right);\r
-    Seg->End  = Right;\r
-\r
-    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
-      TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);\r
-      Drop--;\r
-    }\r
-\r
-    if (Drop != 0) {\r
-      NetbufTrim (Nbuf, Drop, NET_BUF_TAIL);\r
-    }\r
-  }\r
-\r
-  ASSERT (TcpVerifySegment (Nbuf) != 0);\r
-}\r
-\r
-\r
-/**\r
-  Trim off the data outside the tcb's receive window.\r
-\r
-  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
-  @param  Nbuf     Pointer to the NET_BUF containing the received tcp segment.\r
-\r
-**/\r
-VOID\r
-TcpTrimInWnd (\r
-  IN TCP_CB  *Tcb,\r
-  IN NET_BUF *Nbuf\r
-  )\r
-{\r
-  TcpTrimSegment (Nbuf, Tcb->RcvNxt, Tcb->RcvWl2 + Tcb->RcvWnd);\r
-}\r
-\r
-\r
-/**\r
-  Process the data and FIN flag, check whether to deliver\r
-  data to the socket layer.\r
-\r
-  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
-\r
-  @retval 0        No error occurred to deliver data.\r
-  @retval -1       Error condition occurred. Proper response is to reset the\r
-                   connection.\r
-\r
-**/\r
-INTN\r
-TcpDeliverData (\r
-  IN OUT TCP_CB *Tcb\r
-  )\r
-{\r
-  LIST_ENTRY      *Entry;\r
-  NET_BUF         *Nbuf;\r
-  TCP_SEQNO       Seq;\r
-  TCP_SEG         *Seg;\r
-  UINT32          Urgent;\r
-\r
-  ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));\r
-\r
-  //\r
-  // make sure there is some data queued,\r
-  // and TCP is in a proper state\r
-  //\r
-  if (IsListEmpty (&Tcb->RcvQue) || !TCP_CONNECTED (Tcb->State)) {\r
-\r
-    return 0;\r
-  }\r
-\r
-  //\r
-  // Deliver data to the socket layer\r
-  //\r
-  Entry = Tcb->RcvQue.ForwardLink;\r
-  Seq   = Tcb->RcvNxt;\r
-\r
-  while (Entry != &Tcb->RcvQue) {\r
-    Nbuf  = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
-    Seg   = TCPSEG_NETBUF (Nbuf);\r
-\r
-    ASSERT (TcpVerifySegment (Nbuf) != 0);\r
-    ASSERT (Nbuf->Tcp == NULL);\r
-\r
-    if (TCP_SEQ_GT (Seg->Seq, Seq)) {\r
-      break;\r
-    }\r
-\r
-    Entry       = Entry->ForwardLink;\r
-    Seq         = Seg->End;\r
-    Tcb->RcvNxt = Seq;\r
-\r
-    RemoveEntryList (&Nbuf->List);\r
-\r
-    //\r
-    // RFC793 Eighth step: process FIN in sequence\r
-    //\r
-    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
-\r
-      //\r
-      // The peer sends to us junky data after FIN,\r
-      // reset the connection.\r
-      //\r
-      if (!IsListEmpty (&Tcb->RcvQue)) {\r
-        DEBUG ((EFI_D_ERROR, "TcpDeliverData: data received after"\r
-          " FIN from peer of TCB %p, reset connection\n", Tcb));\r
-\r
-        NetbufFree (Nbuf);\r
-        return -1;\r
-      }\r
-\r
-      DEBUG ((EFI_D_NET, "TcpDeliverData: processing FIN "\r
-        "from peer of TCB %p\n", Tcb));\r
-\r
-      switch (Tcb->State) {\r
-      case TCP_SYN_RCVD:\r
-      case TCP_ESTABLISHED:\r
-\r
-        TcpSetState (Tcb, TCP_CLOSE_WAIT);\r
-        break;\r
-\r
-      case TCP_FIN_WAIT_1:\r
-\r
-        if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
-\r
-          TcpSetState (Tcb, TCP_CLOSING);\r
-          break;\r
-        }\r
-\r
-      //\r
-      // fall through\r
-      //\r
-      case TCP_FIN_WAIT_2:\r
-\r
-        TcpSetState (Tcb, TCP_TIME_WAIT);\r
-        TcpClearAllTimer (Tcb);\r
-\r
-        if (Tcb->TimeWaitTimeout != 0) {\r
-\r
-          TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
-        } else {\r
-\r
-          DEBUG ((EFI_D_WARN, "Connection closed immediately "\r
-            "because app disables TIME_WAIT timer for %p\n", Tcb));\r
-\r
-          TcpSendAck (Tcb);\r
-          TcpClose (Tcb);\r
-        }\r
-        break;\r
-\r
-      case TCP_CLOSE_WAIT:\r
-      case TCP_CLOSING:\r
-      case TCP_LAST_ACK:\r
-      case TCP_TIME_WAIT:\r
-        //\r
-        // The peer sends to us junk FIN byte. Discard\r
-        // the buffer then reset the connection\r
-        //\r
-        NetbufFree (Nbuf);\r
-        return -1;\r
-      default:\r
-        break;\r
-      }\r
-\r
-      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
-\r
-      Seg->End--;\r
-    }\r
-\r
-    //\r
-    // Don't delay the ack if PUSH flag is on.\r
-    //\r
-    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_PSH)) {\r
-\r
-      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
-    }\r
-\r
-    if (Nbuf->TotalSize != 0) {\r
-      Urgent = 0;\r
-\r
-      if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
-          TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvUp)) {\r
-\r
-        if (TCP_SEQ_LEQ (Seg->End, Tcb->RcvUp)) {\r
-          Urgent = Nbuf->TotalSize;\r
-        } else {\r
-          Urgent = TCP_SUB_SEQ (Tcb->RcvUp, Seg->Seq) + 1;\r
-        }\r
-      }\r
-\r
-      SockDataRcvd (Tcb->Sk, Nbuf, Urgent);\r
-    }\r
-\r
-    if (TCP_FIN_RCVD (Tcb->State)) {\r
-\r
-      SockNoMoreData (Tcb->Sk);\r
-    }\r
-\r
-    NetbufFree (Nbuf);\r
-  }\r
-\r
-  return 0;\r
-}\r
-\r
-\r
-/**\r
-  Store the data into the reassemble queue.\r
-\r
-  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
-  @param  Nbuf     Pointer to the buffer containing the data to be queued.\r
-\r
-**/\r
-VOID\r
-TcpQueueData (\r
-  IN OUT TCP_CB  *Tcb,\r
-  IN     NET_BUF *Nbuf\r
-  )\r
-{\r
-  TCP_SEG         *Seg;\r
-  LIST_ENTRY      *Head;\r
-  LIST_ENTRY      *Prev;\r
-  LIST_ENTRY      *Cur;\r
-  NET_BUF         *Node;\r
-\r
-  ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));\r
-\r
-  NET_GET_REF (Nbuf);\r
-\r
-  Seg   = TCPSEG_NETBUF (Nbuf);\r
-  Head  = &Tcb->RcvQue;\r
-\r
-  //\r
-  // Fast path to process normal case. That is,\r
-  // no out-of-order segments are received.\r
-  //\r
-  if (IsListEmpty (Head)) {\r
-\r
-    InsertTailList (Head, &Nbuf->List);\r
-    return;\r
-  }\r
-\r
-  //\r
-  // Find the point to insert the buffer\r
-  //\r
-  for (Prev = Head, Cur = Head->ForwardLink;\r
-       Cur != Head;\r
-       Prev = Cur, Cur = Cur->ForwardLink) {\r
-\r
-    Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
-\r
-    if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->Seq)) {\r
-      break;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Check whether the current segment overlaps with the\r
-  // previous segment.\r
-  //\r
-  if (Prev != Head) {\r
-    Node = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);\r
-\r
-    if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->End)) {\r
-\r
-      if (TCP_SEQ_LEQ (Seg->End, TCPSEG_NETBUF (Node)->End)) {\r
-\r
-        NetbufFree (Nbuf);\r
-        return;\r
-      }\r
-\r
-      TcpTrimSegment (Nbuf, TCPSEG_NETBUF (Node)->End, Seg->End);\r
-    }\r
-  }\r
-\r
-  InsertHeadList (Prev, &Nbuf->List);\r
-\r
-  TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
-\r
-  //\r
-  // Check the segments after the insert point.\r
-  //\r
-  while (Cur != Head) {\r
-    Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
-\r
-    if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->End, Seg->End)) {\r
-\r
-      Cur = Cur->ForwardLink;\r
-\r
-      RemoveEntryList (&Node->List);\r
-      NetbufFree (Node);\r
-      continue;\r
-    }\r
-\r
-    if (TCP_SEQ_LT (TCPSEG_NETBUF (Node)->Seq, Seg->End)) {\r
-\r
-      if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->Seq, Seg->Seq)) {\r
-\r
-        RemoveEntryList (&Nbuf->List);\r
-        NetbufFree (Nbuf);\r
-        return ;\r
-      }\r
-\r
-      TcpTrimSegment (Nbuf, Seg->Seq, TCPSEG_NETBUF (Node)->Seq);\r
-      break;\r
-    }\r
-\r
-    Cur = Cur->ForwardLink;\r
-  }\r
-}\r
-\r
-\r
-/**\r
-  Ajust the send queue or the retransmit queue.\r
-\r
-  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
-  @param  Ack      The acknowledge seuqence number of the received segment.\r
-\r
-**/\r
-VOID\r
-TcpAdjustSndQue (\r
-  IN TCP_CB    *Tcb,\r
-  IN TCP_SEQNO Ack\r
-  )\r
-{\r
-  LIST_ENTRY      *Head;\r
-  LIST_ENTRY      *Cur;\r
-  NET_BUF         *Node;\r
-  TCP_SEG         *Seg;\r
-\r
-  Head  = &Tcb->SndQue;\r
-  Cur   = Head->ForwardLink;\r
-\r
-  while (Cur != Head) {\r
-    Node  = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
-    Seg   = TCPSEG_NETBUF (Node);\r
-\r
-    if (TCP_SEQ_GEQ (Seg->Seq, Ack)) {\r
-      break;\r
-    }\r
-\r
-    //\r
-    // Remove completely ACKed segments\r
-    //\r
-    if (TCP_SEQ_LEQ (Seg->End, Ack)) {\r
-      Cur = Cur->ForwardLink;\r
-\r
-      RemoveEntryList (&Node->List);\r
-      NetbufFree (Node);\r
-      continue;\r
-    }\r
-\r
-    TcpTrimSegment (Node, Ack, Seg->End);\r
-    break;\r
-  }\r
-}\r
-\r
-\r
-/**\r
-  Process the received TCP segments.\r
-\r
-  @param  Nbuf     Buffer that contains received TCP segment without IP header.\r
-  @param  Src      Source address of the segment, or the peer's IP address.\r
-  @param  Dst      Destination address of the segment, or the local end's IP\r
-                   address.\r
-\r
-  @retval 0        Segment is processed successfully. It is either accepted or\r
-                   discarded. But no connection is reset by the segment.\r
-  @retval -1       A connection is reset by the segment.\r
-\r
-**/\r
-INTN\r
-TcpInput (\r
-  IN NET_BUF *Nbuf,\r
-  IN UINT32  Src,\r
-  IN UINT32  Dst\r
-  )\r
-{\r
-  TCP_CB      *Tcb;\r
-  TCP_CB      *Parent;\r
-  TCP_OPTION  Option;\r
-  TCP_HEAD    *Head;\r
-  INT32       Len;\r
-  TCP_SEG     *Seg;\r
-  TCP_SEQNO   Right;\r
-  TCP_SEQNO   Urg;\r
-  INT32       Usable;\r
-\r
-  NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
-\r
-  Parent  = NULL;\r
-  Tcb     = NULL;\r
-\r
-  Head    = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
-  ASSERT (Head != NULL);\r
-\r
-  if (Nbuf->TotalSize < sizeof (TCP_HEAD)) {\r
-    DEBUG ((EFI_D_NET, "TcpInput: received a malformed packet\n"));\r
-    goto DISCARD;\r
-  }\r
-\r
-  Len     = Nbuf->TotalSize - (Head->HeadLen << 2);\r
-\r
-  if ((Head->HeadLen < 5) || (Len < 0) ||\r
-      (TcpChecksum (Nbuf, NetPseudoHeadChecksum (Src, Dst, 6, 0)) != 0)) {\r
-\r
-    DEBUG ((EFI_D_NET, "TcpInput: received a malformed packet\n"));\r
-    goto DISCARD;\r
-  }\r
-\r
-  if (TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)) {\r
-    Len++;\r
-  }\r
-\r
-  if (TCP_FLG_ON (Head->Flag, TCP_FLG_FIN)) {\r
-    Len++;\r
-  }\r
-\r
-  Tcb = TcpLocateTcb (\r
-          Head->DstPort,\r
-          Dst,\r
-          Head->SrcPort,\r
-          Src,\r
-          (BOOLEAN) TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)\r
-          );\r
-\r
-  if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {\r
-    DEBUG ((EFI_D_NET, "TcpInput: send reset because no TCB found\n"));\r
-\r
-    Tcb = NULL;\r
-    goto SEND_RESET;\r
-  }\r
-\r
-  Seg = TcpFormatNetbuf (Tcb, Nbuf);\r
-\r
-  //\r
-  // RFC1122 recommended reaction to illegal option\r
-  // (in fact, an illegal option length) is reset.\r
-  //\r
-  if (TcpParseOption (Nbuf->Tcp, &Option) == -1) {\r
-    DEBUG ((EFI_D_ERROR, "TcpInput: reset the peer because"\r
-      " of malformed option for TCB %p\n", Tcb));\r
-\r
-    goto SEND_RESET;\r
-  }\r
-\r
-  //\r
-  // From now on, the segment is headless\r
-  //\r
-  NetbufTrim (Nbuf, (Head->HeadLen << 2), NET_BUF_HEAD);\r
-  Nbuf->Tcp = NULL;\r
-\r
-  //\r
-  // Process the segment in LISTEN state.\r
-  //\r
-  if (Tcb->State == TCP_LISTEN) {\r
-    //\r
-    // First step: Check RST\r
-    //\r
-    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
-      DEBUG ((EFI_D_WARN, "TcpInput: discard a reset segment "\r
-        "for TCB %p in listening\n", Tcb));\r
-\r
-      goto DISCARD;\r
-    }\r
-\r
-    //\r
-    // Second step: Check ACK.\r
-    // Any ACK sent to TCP in LISTEN is reseted.\r
-    //\r
-    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
-      DEBUG ((EFI_D_WARN, "TcpInput: send reset because of"\r
-        " segment with ACK for TCB %p in listening\n", Tcb));\r
-\r
-      goto SEND_RESET;\r
-    }\r
-\r
-    //\r
-    // Third step: Check SYN\r
-    //\r
-    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
-      //\r
-      // create a child TCB to handle the data\r
-      //\r
-      Parent  = Tcb;\r
-\r
-      Tcb     = TcpCloneTcb (Parent);\r
-      if (Tcb == NULL) {\r
-        DEBUG ((EFI_D_ERROR, "TcpInput: discard a segment because"\r
-          " failed to clone a child for TCB %p\n", Tcb));\r
-\r
-        goto DISCARD;\r
-      }\r
-\r
-      DEBUG ((EFI_D_NET, "TcpInput: create a child for TCB %p"\r
-        " in listening\n", Tcb));\r
-\r
-      //\r
-      // init the TCB structure\r
-      //\r
-      Tcb->LocalEnd.Ip    = Dst;\r
-      Tcb->LocalEnd.Port  = Head->DstPort;\r
-      Tcb->RemoteEnd.Ip   = Src;\r
-      Tcb->RemoteEnd.Port = Head->SrcPort;\r
-\r
-      TcpInitTcbLocal (Tcb);\r
-      TcpInitTcbPeer (Tcb, Seg, &Option);\r
-\r
-      TcpSetState (Tcb, TCP_SYN_RCVD);\r
-      TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
-      TcpTrimInWnd (Tcb, Nbuf);\r
-\r
-      goto StepSix;\r
-    }\r
-\r
-    goto DISCARD;\r
-\r
-  } else if (Tcb->State == TCP_SYN_SENT) {\r
-    //\r
-    // First step: Check ACK bit\r
-    //\r
-    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK) && (Seg->Ack != Tcb->Iss + 1)) {\r
-\r
-      DEBUG ((EFI_D_WARN, "TcpInput: send reset because of "\r
-        "wrong ACK received for TCB %p in SYN_SENT\n", Tcb));\r
-\r
-      goto SEND_RESET;\r
-    }\r
-\r
-    //\r
-    // Second step: Check RST bit\r
-    //\r
-    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
-\r
-      if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
-\r
-        DEBUG ((EFI_D_WARN, "TcpInput: connection reset by"\r
-          " peer for TCB %p in SYN_SENT\n", Tcb));\r
-\r
-        SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
-        goto DROP_CONNECTION;\r
-      } else {\r
-\r
-        DEBUG ((EFI_D_WARN, "TcpInput: discard a reset segment "\r
-          "because of no ACK for TCB %p in SYN_SENT\n", Tcb));\r
-\r
-        goto DISCARD;\r
-      }\r
-    }\r
-\r
-    //\r
-    // Third step: Check security and precedence. Skipped\r
-    //\r
-\r
-    //\r
-    // Fourth step: Check SYN. Pay attention to simultaneous open\r
-    //\r
-    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
-\r
-      TcpInitTcbPeer (Tcb, Seg, &Option);\r
-\r
-      if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
-\r
-        Tcb->SndUna = Seg->Ack;\r
-      }\r
-\r
-      TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
-\r
-      if (TCP_SEQ_GT (Tcb->SndUna, Tcb->Iss)) {\r
-\r
-        TcpSetState (Tcb, TCP_ESTABLISHED);\r
-\r
-        TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
-        TcpDeliverData (Tcb);\r
-\r
-        if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&\r
-            TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
-\r
-          TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
-          TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
-        }\r
-\r
-        TcpTrimInWnd (Tcb, Nbuf);\r
-\r
-        TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
-\r
-        DEBUG ((EFI_D_NET, "TcpInput: connection established"\r
-          " for TCB %p in SYN_SENT\n", Tcb));\r
-\r
-        goto StepSix;\r
-      } else {\r
-        //\r
-        // Received a SYN segment without ACK, simultaneous open.\r
-        //\r
-        TcpSetState (Tcb, TCP_SYN_RCVD);\r
-\r
-        ASSERT (Tcb->SndNxt == Tcb->Iss + 1);\r
-        TcpAdjustSndQue (Tcb, Tcb->SndNxt);\r
-\r
-        TcpTrimInWnd (Tcb, Nbuf);\r
-\r
-        DEBUG ((EFI_D_WARN, "TcpInput: simultaneous open "\r
-          "for TCB %p in SYN_SENT\n", Tcb));\r
-\r
-        goto StepSix;\r
-      }\r
-    }\r
-\r
-    goto DISCARD;\r
-  }\r
-\r
-  //\r
-  // Process segment in SYN_RCVD or TCP_CONNECTED states\r
-  //\r
-\r
-  //\r
-  // Clear probe timer since the RecvWindow is opened.\r
-  //\r
-  if (Tcb->ProbeTimerOn && (Seg->Wnd != 0)) {\r
-    TcpClearTimer (Tcb, TCP_TIMER_PROBE);\r
-    Tcb->ProbeTimerOn = FALSE;\r
-  }\r
-\r
-  //\r
-  // First step: Check whether SEG.SEQ is acceptable\r
-  //\r
-  if (TcpSeqAcceptable (Tcb, Seg) == 0) {\r
-    DEBUG ((EFI_D_WARN, "TcpInput: sequence acceptance"\r
-      " test failed for segment of TCB %p\n", Tcb));\r
-\r
-    if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
-      TcpSendAck (Tcb);\r
-    }\r
-\r
-    goto DISCARD;\r
-  }\r
-\r
-  if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) &&\r
-      (Tcb->RcvWl2 == Seg->End) &&\r
-      !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN)) {\r
-\r
-    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
-  }\r
-\r
-  //\r
-  // Second step: Check the RST\r
-  //\r
-  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
-\r
-    DEBUG ((EFI_D_WARN, "TcpInput: connection reset for TCB %p\n", Tcb));\r
-\r
-    if (Tcb->State == TCP_SYN_RCVD) {\r
-\r
-      SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_REFUSED);\r
-\r
-      //\r
-      // This TCB comes from either a LISTEN TCB,\r
-      // or active open TCB with simultanous open.\r
-      // Do NOT signal user CONNECTION refused\r
-      // if it comes from a LISTEN TCB.\r
-      //\r
-    } else if ((Tcb->State == TCP_ESTABLISHED) ||\r
-               (Tcb->State == TCP_FIN_WAIT_1) ||\r
-               (Tcb->State == TCP_FIN_WAIT_2) ||\r
-               (Tcb->State == TCP_CLOSE_WAIT)) {\r
-\r
-      SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
-\r
-    } else {\r
-\r
-    }\r
-\r
-    goto DROP_CONNECTION;\r
-  }\r
-\r
-  //\r
-  // Trim the data and flags.\r
-  //\r
-  TcpTrimInWnd (Tcb, Nbuf);\r
-\r
-  //\r
-  // Third step: Check security and precedence, Ignored\r
-  //\r
-\r
-  //\r
-  // Fourth step: Check the SYN bit.\r
-  //\r
-  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
-\r
-    DEBUG ((EFI_D_WARN, "TcpInput: connection reset "\r
-      "because received extra SYN for TCB %p\n", Tcb));\r
-\r
-    SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
-    goto RESET_THEN_DROP;\r
-  }\r
-\r
-  //\r
-  // Fifth step: Check the ACK\r
-  //\r
-  if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
-    DEBUG ((EFI_D_WARN, "TcpInput: segment discard because"\r
-      " of no ACK for connected TCB %p\n", Tcb));\r
-\r
-    goto DISCARD;\r
-\r
-  }\r
-\r
-  if (Tcb->State == TCP_SYN_RCVD) {\r
-\r
-    if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) &&\r
-        TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt)) {\r
-\r
-      Tcb->SndWnd     = Seg->Wnd;\r
-      Tcb->SndWndMax  = MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
-      Tcb->SndWl1     = Seg->Seq;\r
-      Tcb->SndWl2     = Seg->Ack;\r
-      TcpSetState (Tcb, TCP_ESTABLISHED);\r
-\r
-      TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
-      TcpDeliverData (Tcb);\r
-\r
-      DEBUG ((EFI_D_NET, "TcpInput: connection established "\r
-        " for TCB %p in SYN_RCVD\n", Tcb));\r
-\r
-      //\r
-      // Continue the process as ESTABLISHED state\r
-      //\r
-    } else {\r
-      DEBUG ((EFI_D_WARN, "TcpInput: send reset because of"\r
-        " wrong ACK for TCB %p in SYN_RCVD\n", Tcb));\r
-\r
-      goto SEND_RESET;\r
-    }\r
-  }\r
-\r
-  if (TCP_SEQ_LT (Seg->Ack, Tcb->SndUna)) {\r
-\r
-    DEBUG ((EFI_D_WARN, "TcpInput: ignore the out-of-data"\r
-      " ACK for connected TCB %p\n", Tcb));\r
-\r
-    goto StepSix;\r
-\r
-  } else if (TCP_SEQ_GT (Seg->Ack, Tcb->SndNxt)) {\r
-\r
-    DEBUG ((EFI_D_WARN, "TcpInput: discard segment for "\r
-      "future ACK for connected TCB %p\n", Tcb));\r
-\r
-    TcpSendAck (Tcb);\r
-    goto DISCARD;\r
-  }\r
-\r
-  //\r
-  // From now on: SND.UNA <= SEG.ACK <= SND.NXT.\r
-  //\r
-  if (TCP_FLG_ON (Option.Flag, TCP_OPTION_RCVD_TS)) {\r
-    //\r
-    // update TsRecent as specified in page 16 RFC1323.\r
-    // RcvWl2 equals to the variable "LastAckSent"\r
-    // defined there.\r
-    //\r
-    if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) &&\r
-        TCP_SEQ_LT (Tcb->RcvWl2, Seg->End)) {\r
-\r
-      Tcb->TsRecent     = Option.TSVal;\r
-      Tcb->TsRecentAge  = mTcpTick;\r
-    }\r
-\r
-    TcpComputeRtt (Tcb, TCP_SUB_TIME (mTcpTick, Option.TSEcr));\r
-\r
-  } else if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
-\r
-    ASSERT (Tcb->CongestState == TCP_CONGEST_OPEN);\r
-\r
-    TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
-    TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
-  }\r
-\r
-  if (Seg->Ack == Tcb->SndNxt) {\r
-\r
-    TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
-  } else {\r
-\r
-    TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
-  }\r
-\r
-  //\r
-  // Count duplicate acks.\r
-  //\r
-  if ((Seg->Ack == Tcb->SndUna) &&\r
-      (Tcb->SndUna != Tcb->SndNxt) &&\r
-      (Seg->Wnd == Tcb->SndWnd) &&\r
-      (0 == Len)) {\r
-\r
-    Tcb->DupAck++;\r
-  } else {\r
-\r
-    Tcb->DupAck = 0;\r
-  }\r
-\r
-  //\r
-  // Congestion avoidance, fast recovery and fast retransmission.\r
-  //\r
-  if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) ||\r
-      (Tcb->CongestState == TCP_CONGEST_LOSS)) {\r
-\r
-    if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
-\r
-      if (Tcb->CWnd < Tcb->Ssthresh) {\r
-\r
-        Tcb->CWnd += Tcb->SndMss;\r
-      } else {\r
-\r
-        Tcb->CWnd += MAX (Tcb->SndMss * Tcb->SndMss / Tcb->CWnd, 1);\r
-      }\r
-\r
-      Tcb->CWnd = MIN (Tcb->CWnd, TCP_MAX_WIN << Tcb->SndWndScale);\r
-    }\r
-\r
-    if (Tcb->CongestState == TCP_CONGEST_LOSS) {\r
-      TcpFastLossRecover (Tcb, Seg);\r
-    }\r
-  } else {\r
-\r
-    TcpFastRecover (Tcb, Seg);\r
-  }\r
-\r
-  if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
-\r
-    TcpAdjustSndQue (Tcb, Seg->Ack);\r
-    Tcb->SndUna = Seg->Ack;\r
-\r
-    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&\r
-        TCP_SEQ_LT (Tcb->SndUp, Seg->Ack)) {\r
-\r
-      TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);\r
-    }\r
-  }\r
-\r
-  //\r
-  // Update window info\r
-  //\r
-  if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) ||\r
-      ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack))) {\r
-\r
-    Right = Seg->Ack + Seg->Wnd;\r
-\r
-    if (TCP_SEQ_LT (Right, Tcb->SndWl2 + Tcb->SndWnd)) {\r
-\r
-      if ((Tcb->SndWl1 == Seg->Seq) &&\r
-          (Tcb->SndWl2 == Seg->Ack) &&\r
-          (Len == 0)) {\r
-\r
-        goto NO_UPDATE;\r
-      }\r
-\r
-      DEBUG ((EFI_D_WARN, "TcpInput: peer shrinks the"\r
-        " window for connected TCB %p\n", Tcb));\r
-\r
-      if ((Tcb->CongestState == TCP_CONGEST_RECOVER) &&\r
-          (TCP_SEQ_LT (Right, Tcb->Recover))) {\r
-\r
-        Tcb->Recover = Right;\r
-      }\r
-\r
-      if ((Tcb->CongestState == TCP_CONGEST_LOSS) &&\r
-          (TCP_SEQ_LT (Right, Tcb->LossRecover))) {\r
-\r
-        Tcb->LossRecover = Right;\r
-      }\r
-\r
-      if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {\r
-        //\r
-        // Check for Window Retraction in RFC7923 section 2.4.\r
-        // The lower n bits of the peer's actual receive window is wiped out if TCP\r
-        // window scale is enabled, it will look like the peer is shrinking the window.\r
-        // Check whether the SndNxt is out of the advertised receive window by more than\r
-        // 2^Rcv.Wind.Shift before moving the SndNxt to the left.\r
-        //\r
-        DEBUG (\r
-          (EFI_D_WARN,\r
-          "TcpInput: peer advise negative useable window for connected TCB %p\n",\r
-          Tcb)\r
-          );\r
-        Usable = TCP_SUB_SEQ (Tcb->SndNxt, Right);\r
-        if ((Usable >> Tcb->SndWndScale) > 0) {\r
-          DEBUG (\r
-            (EFI_D_WARN,\r
-            "TcpInput: SndNxt is out of window by more than window scale for TCB %p\n",\r
-            Tcb)\r
-            );\r
-          Tcb->SndNxt = Right;\r
-        }\r
-        if (Right == Tcb->SndUna) {\r
-\r
-          TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
-          TcpSetProbeTimer (Tcb);\r
-        }\r
-      }\r
-    }\r
-\r
-    Tcb->SndWnd     = Seg->Wnd;\r
-    Tcb->SndWndMax  = MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
-    Tcb->SndWl1     = Seg->Seq;\r
-    Tcb->SndWl2     = Seg->Ack;\r
-  }\r
-\r
-NO_UPDATE:\r
-\r
-  if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) &&\r
-      (Tcb->SndUna == Tcb->SndNxt)) {\r
-\r
-    DEBUG ((EFI_D_NET, "TcpInput: local FIN is ACKed by"\r
-      " peer for connected TCB %p\n", Tcb));\r
-\r
-    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED);\r
-  }\r
-\r
-  //\r
-  // Transit the state if proper.\r
-  //\r
-  switch (Tcb->State) {\r
-  case TCP_FIN_WAIT_1:\r
-\r
-    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
-\r
-      TcpSetState (Tcb, TCP_FIN_WAIT_2);\r
-\r
-      TcpClearAllTimer (Tcb);\r
-      TcpSetTimer (Tcb, TCP_TIMER_FINWAIT2, Tcb->FinWait2Timeout);\r
-    }\r
-\r
-  case TCP_FIN_WAIT_2:\r
-\r
-    break;\r
-\r
-  case TCP_CLOSE_WAIT:\r
-    break;\r
-\r
-  case TCP_CLOSING:\r
-\r
-    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
-\r
-      TcpSetState (Tcb, TCP_TIME_WAIT);\r
-\r
-      TcpClearAllTimer (Tcb);\r
-\r
-      if (Tcb->TimeWaitTimeout != 0) {\r
-\r
-        TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
-      } else {\r
-\r
-        DEBUG ((EFI_D_WARN, "Connection closed immediately "\r
-          "because app disables TIME_WAIT timer for %p\n", Tcb));\r
-\r
-        TcpClose (Tcb);\r
-      }\r
-    }\r
-    break;\r
-\r
-  case TCP_LAST_ACK:\r
-\r
-    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
-\r
-      TcpSetState (Tcb, TCP_CLOSED);\r
-    }\r
-\r
-    break;\r
-\r
-  case TCP_TIME_WAIT:\r
-\r
-    TcpSendAck (Tcb);\r
-\r
-    if (Tcb->TimeWaitTimeout != 0) {\r
-\r
-      TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
-    } else {\r
-\r
-      DEBUG ((EFI_D_WARN, "Connection closed immediately "\r
-        "because app disables TIME_WAIT timer for %p\n", Tcb));\r
-\r
-      TcpClose (Tcb);\r
-    }\r
-    break;\r
-\r
-  default:\r
-    break;\r
-  }\r
-\r
-  //\r
-  // Sixth step: Check the URG bit.update the Urg point\r
-  // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.\r
-  //\r
-StepSix:\r
-\r
-  Tcb->Idle = 0;\r
-  TcpSetKeepaliveTimer (Tcb);\r
-\r
-  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) &&\r
-      !TCP_FIN_RCVD (Tcb->State))\r
-  {\r
-\r
-    DEBUG ((EFI_D_NET, "TcpInput: received urgent data "\r
-      "from peer for connected TCB %p\n", Tcb));\r
-\r
-    Urg = Seg->Seq + Seg->Urg;\r
-\r
-    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
-        TCP_SEQ_GT (Urg, Tcb->RcvUp)) {\r
-\r
-      Tcb->RcvUp = Urg;\r
-    } else {\r
-\r
-      Tcb->RcvUp = Urg;\r
-      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG);\r
-    }\r
-  }\r
-\r
-  //\r
-  // Seventh step: Process the segment data\r
-  //\r
-  if (Seg->End != Seg->Seq) {\r
-\r
-    if (TCP_FIN_RCVD (Tcb->State)) {\r
-\r
-      DEBUG ((EFI_D_WARN, "TcpInput: connection reset because"\r
-        " data is lost for connected TCB %p\n", Tcb));\r
-\r
-      goto RESET_THEN_DROP;\r
-    }\r
-\r
-    if (TCP_LOCAL_CLOSED (Tcb->State) && (Nbuf->TotalSize != 0)) {\r
-      DEBUG ((EFI_D_WARN, "TcpInput: connection reset because"\r
-        " data is lost for connected TCB %p\n", Tcb));\r
-\r
-      goto RESET_THEN_DROP;\r
-    }\r
-\r
-    TcpQueueData (Tcb, Nbuf);\r
-    if (TcpDeliverData (Tcb) == -1) {\r
-      goto RESET_THEN_DROP;\r
-    }\r
-\r
-    if (!IsListEmpty (&Tcb->RcvQue)) {\r
-      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
-    }\r
-  }\r
-\r
-  //\r
-  // Eighth step: check the FIN.\r
-  // This step is moved to TcpDeliverData. FIN will be\r
-  // processed in sequence there. Check the comments in\r
-  // the beginning of the file header for information.\r
-  //\r
-\r
-  //\r
-  // Tcb is a new child of the listening Parent,\r
-  // commit it.\r
-  //\r
-  if (Parent != NULL) {\r
-    Tcb->Parent = Parent;\r
-    TcpInsertTcb (Tcb);\r
-  }\r
-\r
-  if ((Tcb->State != TCP_CLOSED) &&\r
-      (TcpToSendData (Tcb, 0) == 0) &&\r
-      (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Nbuf->TotalSize != 0))) {\r
-\r
-    TcpToSendAck (Tcb);\r
-  }\r
-\r
-  NetbufFree (Nbuf);\r
-  return 0;\r
-\r
-RESET_THEN_DROP:\r
-  TcpSendReset (Tcb, Head, Len, Dst, Src);\r
-\r
-DROP_CONNECTION:\r
-  ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));\r
-\r
-  NetbufFree (Nbuf);\r
-  TcpClose (Tcb);\r
-\r
-  return -1;\r
-\r
-SEND_RESET:\r
-\r
-  TcpSendReset (Tcb, Head, Len, Dst, Src);\r
-\r
-DISCARD:\r
-\r
-  //\r
-  // Tcb is a child of Parent, and it doesn't survive\r
-  //\r
-  DEBUG ((EFI_D_WARN, "Tcp4Input: Discard a packet\n"));\r
-  NetbufFree (Nbuf);\r
-\r
-  if ((Parent != NULL) && (Tcb != NULL)) {\r
-\r
-    ASSERT (Tcb->Sk != NULL);\r
-    TcpClose (Tcb);\r
-  }\r
-\r
-  return 0;\r
-}\r
-\r
-\r
-/**\r
-  Process the received ICMP error messages for TCP.\r
-\r
-  @param  Nbuf     Buffer that contains part of the TCP segment without IP header\r
-                   truncated from the ICMP error packet.\r
-  @param  IcmpErr  The ICMP error code interpreted from ICMP error packet.\r
-  @param  Src      Source address of the ICMP error message.\r
-  @param  Dst      Destination address of the ICMP error message.\r
-\r
-**/\r
-VOID\r
-TcpIcmpInput (\r
-  IN NET_BUF     *Nbuf,\r
-  IN UINT8       IcmpErr,\r
-  IN UINT32      Src,\r
-  IN UINT32      Dst\r
-  )\r
-{\r
-  TCP_HEAD         *Head;\r
-  TCP_CB           *Tcb;\r
-  TCP_SEQNO        Seq;\r
-  EFI_STATUS       IcmpErrStatus;\r
-  BOOLEAN          IcmpErrIsHard;\r
-  BOOLEAN          IcmpErrNotify;\r
-\r
-  if (Nbuf->TotalSize < sizeof (TCP_HEAD)) {\r
-    goto CLEAN_EXIT;\r
-  }\r
-\r
-  Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
-  ASSERT (Head != NULL);\r
-  Tcb = TcpLocateTcb (\r
-          Head->DstPort,\r
-          Dst,\r
-          Head->SrcPort,\r
-          Src,\r
-          FALSE\r
-          );\r
-  if (Tcb == NULL || Tcb->State == TCP_CLOSED) {\r
-\r
-    goto CLEAN_EXIT;\r
-  }\r
-\r
-  //\r
-  // Validate the sequence number.\r
-  //\r
-  Seq = NTOHL (Head->Seq);\r
-  if (!(TCP_SEQ_LEQ (Tcb->SndUna, Seq) && TCP_SEQ_LT (Seq, Tcb->SndNxt))) {\r
-\r
-    goto CLEAN_EXIT;\r
-  }\r
-\r
-  IcmpErrStatus = IpIoGetIcmpErrStatus (\r
-                    IcmpErr,\r
-                    IP_VERSION_4,\r
-                    &IcmpErrIsHard,\r
-                    &IcmpErrNotify\r
-                    );\r
-\r
-  if (IcmpErrNotify) {\r
-\r
-    SOCK_ERROR (Tcb->Sk, IcmpErrStatus);\r
-  }\r
-\r
-  if (IcmpErrIsHard) {\r
-\r
-    TcpClose (Tcb);\r
-  }\r
-\r
-CLEAN_EXIT:\r
-  NetbufFree (Nbuf);\r
-}\r