]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/TcpDxe/TcpInput.c
StandaloneMmPkg: Describe the declaration and definition files.
[mirror_edk2.git] / NetworkPkg / TcpDxe / TcpInput.c
index d0118f1d886d8bd128669047ae066d360ad50f60..5b74fdcdc362ff3f1f5888920bf5c2a0a90db6be 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   TCP input process routines.\r
 \r
-  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
@@ -31,7 +31,7 @@ TcpSeqAcceptable (
   IN TCP_SEG *Seg\r
   )\r
 {\r
-  return (TCP_SEQ_LEQ (Tcb->RcvWl2, Seg->End) &&\r
+  return (TCP_SEQ_LEQ (Tcb->RcvNxt, Seg->End) &&\r
           TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2 + Tcb->RcvWnd));\r
 }\r
 \r
@@ -74,7 +74,7 @@ TcpFastRecover (
     Tcb->CWnd = Tcb->Ssthresh + 3 * Tcb->SndMss;\r
 \r
     DEBUG (\r
-      (EFI_D_INFO,\r
+      (EFI_D_NET,\r
       "TcpFastRecover: enter fast retransmission for TCB %p, recover point is %d\n",\r
       Tcb,\r
       Tcb->Recover)\r
@@ -97,7 +97,7 @@ TcpFastRecover (
     //\r
     Tcb->CWnd += Tcb->SndMss;\r
     DEBUG (\r
-      (EFI_D_INFO,\r
+      (EFI_D_NET,\r
       "TcpFastRecover: received another duplicated ACK (%d) for TCB %p\n",\r
       Seg->Ack,\r
       Tcb)\r
@@ -121,7 +121,7 @@ TcpFastRecover (
 \r
       Tcb->CongestState = TCP_CONGEST_OPEN;\r
       DEBUG (\r
-        (EFI_D_INFO,\r
+        (EFI_D_NET,\r
         "TcpFastRecover: received a full ACK(%d) for TCB %p, exit fast recovery\n",\r
         Seg->Ack,\r
         Tcb)\r
@@ -150,7 +150,7 @@ TcpFastRecover (
       Tcb->CWnd -= Acked;\r
 \r
       DEBUG (\r
-        (EFI_D_INFO,\r
+        (EFI_D_NET,\r
         "TcpFastRecover: received a partial ACK(%d) for TCB %p\n",\r
         Seg->Ack,\r
         Tcb)\r
@@ -188,7 +188,7 @@ TcpFastLossRecover (
       Tcb->CongestState = TCP_CONGEST_OPEN;\r
 \r
       DEBUG (\r
-        (EFI_D_INFO,\r
+        (EFI_D_NET,\r
         "TcpFastLossRecover: received a full ACK(%d) for TCB %p\n",\r
         Seg->Ack,\r
         Tcb)\r
@@ -202,7 +202,7 @@ TcpFastLossRecover (
       //\r
       TcpRetransmit (Tcb, Seg->Ack);\r
       DEBUG (\r
-        (EFI_D_INFO,\r
+        (EFI_D_NET,\r
         "TcpFastLossRecover: received a partial ACK(%d) for TCB %p\n",\r
         Seg->Ack,\r
         Tcb)\r
@@ -264,7 +264,7 @@ TcpComputeRtt (
   }\r
 \r
   DEBUG (\r
-    (EFI_D_INFO,\r
+    (EFI_D_NET,\r
     "TcpComputeRtt: new RTT for TCB %p computed SRTT: %d RTTVAR: %d RTO: %d\n",\r
     Tcb,\r
     Tcb->SRtt,\r
@@ -281,8 +281,11 @@ TcpComputeRtt (
   @param[in]  Left     The sequence number of the window's left edge.\r
   @param[in]  Right    The sequence number of the window's right edge.\r
 \r
+  @retval     0        The segment is broken.\r
+  @retval     1        The segment is in good shape.\r
+\r
 **/\r
-VOID\r
+INTN\r
 TcpTrimSegment (\r
   IN NET_BUF   *Nbuf,\r
   IN TCP_SEQNO Left,\r
@@ -306,7 +309,7 @@ TcpTrimSegment (
 \r
     Seg->Seq = Seg->End;\r
     NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_HEAD);\r
-    return;\r
+    return 1;\r
   }\r
 \r
   //\r
@@ -359,7 +362,7 @@ TcpTrimSegment (
     }\r
   }\r
 \r
-  ASSERT (TcpVerifySegment (Nbuf) != 0);\r
+  return TcpVerifySegment (Nbuf);\r
 }\r
 \r
 /**\r
@@ -368,14 +371,17 @@ TcpTrimSegment (
   @param[in]  Tcb      Pointer to the TCP_CB of this TCP instance.\r
   @param[in]  Nbuf     Pointer to the NET_BUF containing the received tcp segment.\r
 \r
+  @retval     0        The segment is broken.\r
+  @retval     1        The segment is in good shape.\r
+\r
 **/\r
-VOID\r
+INTN\r
 TcpTrimInWnd (\r
   IN TCP_CB  *Tcb,\r
   IN NET_BUF *Nbuf\r
   )\r
 {\r
-  TcpTrimSegment (Nbuf, Tcb->RcvNxt, Tcb->RcvWl2 + Tcb->RcvWnd);\r
+  return TcpTrimSegment (Nbuf, Tcb->RcvNxt, Tcb->RcvWl2 + Tcb->RcvWnd);\r
 }\r
 \r
 /**\r
@@ -421,7 +427,16 @@ TcpDeliverData (
     Nbuf  = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
     Seg   = TCPSEG_NETBUF (Nbuf);\r
 \r
-    ASSERT (TcpVerifySegment (Nbuf) != 0);\r
+    if (TcpVerifySegment (Nbuf) == 0) {\r
+      DEBUG (\r
+        (EFI_D_ERROR,\r
+        "TcpToSendData: discard a broken segment for TCB %p\n",\r
+        Tcb)\r
+        );\r
+      NetbufFree (Nbuf);\r
+      return -1;\r
+    }\r
+\r
     ASSERT (Nbuf->Tcp == NULL);\r
 \r
     if (TCP_SEQ_GT (Seg->Seq, Seq)) {\r
@@ -455,7 +470,7 @@ TcpDeliverData (
       }\r
 \r
       DEBUG (\r
-        (EFI_D_INFO,\r
+        (EFI_D_NET,\r
         "TcpDeliverData: processing FIN from peer of TCB %p\n",\r
         Tcb)\r
         );\r
@@ -561,8 +576,11 @@ TcpDeliverData (
   @param[in, out]  Tcb   Pointer to the TCP_CB of this TCP instance.\r
   @param[in]       Nbuf  Pointer to the buffer containing the data to be queued.\r
 \r
+  @retval          0     An error condition occurred.\r
+  @retval          1     No error occurred to queue data.\r
+\r
 **/\r
-VOID\r
+INTN\r
 TcpQueueData (\r
   IN OUT TCP_CB  *Tcb,\r
   IN     NET_BUF *Nbuf\r
@@ -588,7 +606,7 @@ TcpQueueData (
   if (IsListEmpty (Head)) {\r
 \r
     InsertTailList (Head, &Nbuf->List);\r
-    return;\r
+    return 1;\r
   }\r
 \r
   //\r
@@ -615,12 +633,12 @@ TcpQueueData (
     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
+        return 1;\r
       }\r
 \r
-      TcpTrimSegment (Nbuf, TCPSEG_NETBUF (Node)->End, Seg->End);\r
+      if (TcpTrimSegment (Nbuf, TCPSEG_NETBUF (Node)->End, Seg->End) == 0) {\r
+        return 0;\r
+      }\r
     }\r
   }\r
 \r
@@ -648,16 +666,20 @@ TcpQueueData (
       if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->Seq, Seg->Seq)) {\r
 \r
         RemoveEntryList (&Nbuf->List);\r
-        NetbufFree (Nbuf);\r
-        return;\r
+        return 1;\r
       }\r
 \r
-      TcpTrimSegment (Nbuf, Seg->Seq, TCPSEG_NETBUF (Node)->Seq);\r
+      if (TcpTrimSegment (Nbuf, Seg->Seq, TCPSEG_NETBUF (Node)->Seq) == 0) {\r
+        RemoveEntryList (&Nbuf->List);\r
+        return 0;\r
+      }\r
       break;\r
     }\r
 \r
     Cur = Cur->ForwardLink;\r
   }\r
+\r
+  return 1;\r
 }\r
 \r
 \r
@@ -667,8 +689,11 @@ TcpQueueData (
   @param[in]  Tcb      Pointer to the TCP_CB of this TCP instance.\r
   @param[in]  Ack      The acknowledge seuqence number of the received segment.\r
 \r
+  @retval          0     An error condition occurred.\r
+  @retval          1     No error occurred.\r
+\r
 **/\r
-VOID\r
+INTN\r
 TcpAdjustSndQue (\r
   IN TCP_CB    *Tcb,\r
   IN TCP_SEQNO Ack\r
@@ -701,9 +726,10 @@ TcpAdjustSndQue (
       continue;\r
     }\r
 \r
-    TcpTrimSegment (Node, Ack, Seg->End);\r
-    break;\r
+    return TcpTrimSegment (Node, Ack, Seg->End);\r
   }\r
+\r
+  return 1;\r
 }\r
 \r
 /**\r
@@ -738,6 +764,7 @@ TcpInput (
   TCP_SEQNO   Right;\r
   TCP_SEQNO   Urg;\r
   UINT16      Checksum;\r
+  INT32       Usable;\r
 \r
   ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));\r
 \r
@@ -748,11 +775,18 @@ TcpInput (
 \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
 \r
-    DEBUG ((EFI_D_INFO, "TcpInput: received a malformed packet\n"));\r
+    DEBUG ((EFI_D_NET, "TcpInput: received a malformed packet\n"));\r
+\r
     goto DISCARD;\r
   }\r
 \r
@@ -787,7 +821,7 @@ TcpInput (
           );\r
 \r
   if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {\r
-    DEBUG ((EFI_D_INFO, "TcpInput: send reset because no TCB found\n"));\r
+    DEBUG ((EFI_D_NET, "TcpInput: send reset because no TCB found\n"));\r
 \r
     Tcb = NULL;\r
     goto SEND_RESET;\r
@@ -867,7 +901,7 @@ TcpInput (
       }\r
 \r
       DEBUG (\r
-        (EFI_D_INFO,\r
+        (EFI_D_NET,\r
         "TcpInput: create a child for TCB %p in listening\n",\r
         Tcb)\r
         );\r
@@ -885,7 +919,15 @@ TcpInput (
 \r
       TcpSetState (Tcb, TCP_SYN_RCVD);\r
       TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
-      TcpTrimInWnd (Tcb, Nbuf);\r
+      if (TcpTrimInWnd (Tcb, Nbuf) == 0) {\r
+        DEBUG (\r
+          (EFI_D_ERROR,\r
+          "TcpInput: discard a broken segment for TCB %p\n",\r
+          Tcb)\r
+          );\r
+\r
+        goto DISCARD;\r
+      }\r
 \r
       goto StepSix;\r
     }\r
@@ -967,12 +1009,20 @@ TcpInput (
           TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
         }\r
 \r
-        TcpTrimInWnd (Tcb, Nbuf);\r
+        if (TcpTrimInWnd (Tcb, Nbuf) == 0) {\r
+          DEBUG (\r
+            (EFI_D_ERROR,\r
+            "TcpInput: discard a broken segment for TCB %p\n",\r
+            Tcb)\r
+            );\r
+\r
+          goto DISCARD;\r
+        }\r
 \r
         TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
 \r
         DEBUG (\r
-          (EFI_D_INFO,\r
+          (EFI_D_NET,\r
           "TcpInput: connection established for TCB %p in SYN_SENT\n",\r
           Tcb)\r
           );\r
@@ -985,9 +1035,16 @@ TcpInput (
         TcpSetState (Tcb, TCP_SYN_RCVD);\r
 \r
         ASSERT (Tcb->SndNxt == Tcb->Iss + 1);\r
-        TcpAdjustSndQue (Tcb, Tcb->SndNxt);\r
 \r
-        TcpTrimInWnd (Tcb, Nbuf);\r
+        if (TcpAdjustSndQue (Tcb, Tcb->SndNxt) == 0 || TcpTrimInWnd (Tcb, Nbuf) == 0) {\r
+          DEBUG (\r
+            (EFI_D_ERROR,\r
+            "TcpInput: discard a broken segment for TCB %p\n",\r
+            Tcb)\r
+            );\r
+\r
+          goto DISCARD;\r
+        }\r
 \r
         DEBUG (\r
           (EFI_D_WARN,\r
@@ -1073,7 +1130,15 @@ TcpInput (
   //\r
   // Trim the data and flags.\r
   //\r
-  TcpTrimInWnd (Tcb, Nbuf);\r
+  if (TcpTrimInWnd (Tcb, Nbuf) == 0) {\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "TcpInput: discard a broken segment for TCB %p\n",\r
+      Tcb)\r
+      );\r
+\r
+    goto DISCARD;\r
+  }\r
 \r
   //\r
   // Third step: Check security and precedence, Ignored\r
@@ -1127,7 +1192,7 @@ TcpInput (
       TcpDeliverData (Tcb);\r
 \r
       DEBUG (\r
-        (EFI_D_INFO,\r
+        (EFI_D_NET,\r
         "TcpInput: connection established for TCB %p in SYN_RCVD\n",\r
         Tcb)\r
         );\r
@@ -1248,7 +1313,16 @@ TcpInput (
 \r
   if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
 \r
-    TcpAdjustSndQue (Tcb, Seg->Ack);\r
+    if (TcpAdjustSndQue (Tcb, Seg->Ack) == 0) {\r
+      DEBUG (\r
+        (EFI_D_ERROR,\r
+        "TcpInput: discard a broken segment for TCB %p\n",\r
+        Tcb)\r
+        );\r
+\r
+      goto DISCARD;\r
+    }\r
+\r
     Tcb->SndUna = Seg->Ack;\r
 \r
     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&\r
@@ -1299,9 +1373,27 @@ TcpInput (
       }\r
 \r
       if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {\r
-\r
-        Tcb->SndNxt = Right;\r
-\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
@@ -1323,7 +1415,7 @@ NO_UPDATE:
   {\r
 \r
     DEBUG (\r
-      (EFI_D_INFO,\r
+      (EFI_D_NET,\r
       "TcpInput: local FIN is ACKed by peer for connected TCB %p\n",\r
       Tcb)\r
       );\r
@@ -1419,7 +1511,7 @@ StepSix:
   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) && !TCP_FIN_RCVD (Tcb->State)) {\r
 \r
     DEBUG (\r
-      (EFI_D_INFO,\r
+      (EFI_D_NET,\r
       "TcpInput: received urgent data from peer for connected TCB %p\n",\r
       Tcb)\r
       );\r
@@ -1463,7 +1555,16 @@ StepSix:
       goto RESET_THEN_DROP;\r
     }\r
 \r
-    TcpQueueData (Tcb, Nbuf);\r
+    if (TcpQueueData (Tcb, Nbuf) == 0) {\r
+      DEBUG (\r
+        (EFI_D_ERROR,\r
+        "TcpInput: discard a broken segment for TCB %p\n",\r
+        Tcb)\r
+        );\r
+\r
+      goto DISCARD;\r
+    }\r
+\r
     if (TcpDeliverData (Tcb) == -1) {\r
       goto RESET_THEN_DROP;\r
     }\r
@@ -1560,6 +1661,10 @@ TcpIcmpInput (
   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
 \r