Home | History | Annotate | Download | only in TcpDxe
      1 /** @file
      2   TCP input process routines.
      3 
      4   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php.
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "TcpMain.h"
     17 
     18 /**
     19   Check whether the sequence number of the incoming segment is acceptable.
     20 
     21   @param[in]  Tcb Pointer to the TCP_CB of this TCP instance.
     22   @param[in]  Seg Pointer to the incoming segment.
     23 
     24   @retval 1       The sequence number is acceptable.
     25   @retval 0       The sequence number is not acceptable.
     26 
     27 **/
     28 INTN
     29 TcpSeqAcceptable (
     30   IN TCP_CB  *Tcb,
     31   IN TCP_SEG *Seg
     32   )
     33 {
     34   return (TCP_SEQ_LEQ (Tcb->RcvWl2, Seg->End) &&
     35           TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2 + Tcb->RcvWnd));
     36 }
     37 
     38 /**
     39   NewReno fast recovery defined in RFC3782.
     40 
     41   @param[in, out]  Tcb      Pointer to the TCP_CB of this TCP instance.
     42   @param[in]       Seg      Segment that triggers the fast recovery.
     43 
     44 **/
     45 VOID
     46 TcpFastRecover (
     47   IN OUT TCP_CB  *Tcb,
     48   IN     TCP_SEG *Seg
     49   )
     50 {
     51   UINT32  FlightSize;
     52   UINT32  Acked;
     53 
     54   //
     55   // Step 1: Three duplicate ACKs and not in fast recovery
     56   //
     57   if (Tcb->CongestState != TCP_CONGEST_RECOVER) {
     58 
     59     //
     60     // Step 1A: Invoking fast retransmission.
     61     //
     62     FlightSize        = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);
     63 
     64     Tcb->Ssthresh     = MAX (FlightSize >> 1, (UINT32) (2 * Tcb->SndMss));
     65     Tcb->Recover      = Tcb->SndNxt;
     66 
     67     Tcb->CongestState = TCP_CONGEST_RECOVER;
     68     TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
     69 
     70     //
     71     // Step 2: Entering fast retransmission
     72     //
     73     TcpRetransmit (Tcb, Tcb->SndUna);
     74     Tcb->CWnd = Tcb->Ssthresh + 3 * Tcb->SndMss;
     75 
     76     DEBUG (
     77       (EFI_D_INFO,
     78       "TcpFastRecover: enter fast retransmission for TCB %p, recover point is %d\n",
     79       Tcb,
     80       Tcb->Recover)
     81       );
     82     return;
     83   }
     84 
     85   //
     86   // During fast recovery, execute Step 3, 4, 5 of RFC3782
     87   //
     88   if (Seg->Ack == Tcb->SndUna) {
     89 
     90     //
     91     // Step 3: Fast Recovery,
     92     // If this is a duplicated ACK, increse Cwnd by SMSS.
     93     //
     94 
     95     // Step 4 is skipped here only to be executed later
     96     // by TcpToSendData
     97     //
     98     Tcb->CWnd += Tcb->SndMss;
     99     DEBUG (
    100       (EFI_D_INFO,
    101       "TcpFastRecover: received another duplicated ACK (%d) for TCB %p\n",
    102       Seg->Ack,
    103       Tcb)
    104       );
    105 
    106   } else {
    107 
    108     //
    109     // New data is ACKed, check whether it is a
    110     // full ACK or partial ACK
    111     //
    112     if (TCP_SEQ_GEQ (Seg->Ack, Tcb->Recover)) {
    113 
    114       //
    115       // Step 5 - Full ACK:
    116       // deflate the congestion window, and exit fast recovery
    117       //
    118       FlightSize        = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);
    119 
    120       Tcb->CWnd         = MIN (Tcb->Ssthresh, FlightSize + Tcb->SndMss);
    121 
    122       Tcb->CongestState = TCP_CONGEST_OPEN;
    123       DEBUG (
    124         (EFI_D_INFO,
    125         "TcpFastRecover: received a full ACK(%d) for TCB %p, exit fast recovery\n",
    126         Seg->Ack,
    127         Tcb)
    128         );
    129 
    130     } else {
    131 
    132       //
    133       // Step 5 - Partial ACK:
    134       // fast retransmit the first unacknowledge field
    135       // , then deflate the CWnd
    136       //
    137       TcpRetransmit (Tcb, Seg->Ack);
    138       Acked = TCP_SUB_SEQ (Seg->Ack, Tcb->SndUna);
    139 
    140       //
    141       // Deflate the CWnd by the amount of new data
    142       // ACKed by SEG.ACK. If more than one SMSS data
    143       // is ACKed, add back SMSS byte to CWnd after
    144       //
    145       if (Acked >= Tcb->SndMss) {
    146         Acked -= Tcb->SndMss;
    147 
    148       }
    149 
    150       Tcb->CWnd -= Acked;
    151 
    152       DEBUG (
    153         (EFI_D_INFO,
    154         "TcpFastRecover: received a partial ACK(%d) for TCB %p\n",
    155         Seg->Ack,
    156         Tcb)
    157         );
    158 
    159     }
    160   }
    161 }
    162 
    163 /**
    164   NewReno fast loss recovery defined in RFC3792.
    165 
    166   @param[in, out]  Tcb      Pointer to the TCP_CB of this TCP instance.
    167   @param[in]       Seg      Segment that triggers the fast loss recovery.
    168 
    169 **/
    170 VOID
    171 TcpFastLossRecover (
    172   IN OUT TCP_CB  *Tcb,
    173   IN     TCP_SEG *Seg
    174   )
    175 {
    176   if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {
    177 
    178     //
    179     // New data is ACKed, check whether it is a
    180     // full ACK or partial ACK
    181     //
    182     if (TCP_SEQ_GEQ (Seg->Ack, Tcb->LossRecover)) {
    183 
    184       //
    185       // Full ACK: exit the loss recovery.
    186       //
    187       Tcb->LossTimes    = 0;
    188       Tcb->CongestState = TCP_CONGEST_OPEN;
    189 
    190       DEBUG (
    191         (EFI_D_INFO,
    192         "TcpFastLossRecover: received a full ACK(%d) for TCB %p\n",
    193         Seg->Ack,
    194         Tcb)
    195         );
    196 
    197     } else {
    198 
    199       //
    200       // Partial ACK:
    201       // fast retransmit the first unacknowledge field.
    202       //
    203       TcpRetransmit (Tcb, Seg->Ack);
    204       DEBUG (
    205         (EFI_D_INFO,
    206         "TcpFastLossRecover: received a partial ACK(%d) for TCB %p\n",
    207         Seg->Ack,
    208         Tcb)
    209         );
    210     }
    211   }
    212 }
    213 
    214 /**
    215   Compute the RTT as specified in RFC2988.
    216 
    217   @param[in, out]  Tcb      Pointer to the TCP_CB of this TCP instance.
    218   @param[in]       Measure  Currently measured RTT in heartbeats.
    219 
    220 **/
    221 VOID
    222 TcpComputeRtt (
    223   IN OUT TCP_CB *Tcb,
    224   IN     UINT32 Measure
    225   )
    226 {
    227   INT32 Var;
    228 
    229   //
    230   // Step 2.3: Compute the RTO for subsequent RTT measurement.
    231   //
    232   if (Tcb->SRtt != 0) {
    233 
    234     Var = Tcb->SRtt - (Measure << TCP_RTT_SHIFT);
    235 
    236     if (Var < 0) {
    237       Var = -Var;
    238     }
    239 
    240     Tcb->RttVar = (3 * Tcb->RttVar + Var) >> 2;
    241     Tcb->SRtt   = 7 * (Tcb->SRtt >> 3) + Measure;
    242 
    243   } else {
    244     //
    245     // Step 2.2: compute the first RTT measure
    246     //
    247     Tcb->SRtt   = Measure << TCP_RTT_SHIFT;
    248     Tcb->RttVar = Measure << (TCP_RTT_SHIFT - 1);
    249   }
    250 
    251   Tcb->Rto = (Tcb->SRtt + MAX (8, 4 * Tcb->RttVar)) >> TCP_RTT_SHIFT;
    252 
    253   //
    254   // Step 2.4: Limit the RTO to at least 1 second
    255   // Step 2.5: Limit the RTO to a maxium value that
    256   // is at least 60 second
    257   //
    258   if (Tcb->Rto < TCP_RTO_MIN) {
    259     Tcb->Rto = TCP_RTO_MIN;
    260 
    261   } else if (Tcb->Rto > TCP_RTO_MAX) {
    262     Tcb->Rto = TCP_RTO_MAX;
    263 
    264   }
    265 
    266   DEBUG (
    267     (EFI_D_INFO,
    268     "TcpComputeRtt: new RTT for TCB %p computed SRTT: %d RTTVAR: %d RTO: %d\n",
    269     Tcb,
    270     Tcb->SRtt,
    271     Tcb->RttVar,
    272     Tcb->Rto)
    273     );
    274 
    275 }
    276 
    277 /**
    278   Trim the data; SYN and FIN to fit into the window defined by Left and Right.
    279 
    280   @param[in]  Nbuf     The buffer that contains a received TCP segment without an IP header.
    281   @param[in]  Left     The sequence number of the window's left edge.
    282   @param[in]  Right    The sequence number of the window's right edge.
    283 
    284 **/
    285 VOID
    286 TcpTrimSegment (
    287   IN NET_BUF   *Nbuf,
    288   IN TCP_SEQNO Left,
    289   IN TCP_SEQNO Right
    290   )
    291 {
    292   TCP_SEG   *Seg;
    293   TCP_SEQNO Urg;
    294   UINT32    Drop;
    295 
    296   Seg = TCPSEG_NETBUF (Nbuf);
    297 
    298   //
    299   // If the segment is completely out of window,
    300   // truncate every thing, include SYN and FIN.
    301   //
    302   if (TCP_SEQ_LEQ (Seg->End, Left) || TCP_SEQ_LEQ (Right, Seg->Seq)) {
    303 
    304     TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);
    305     TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);
    306 
    307     Seg->Seq = Seg->End;
    308     NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_HEAD);
    309     return;
    310   }
    311 
    312   //
    313   // Adjust the buffer header
    314   //
    315   if (TCP_SEQ_LT (Seg->Seq, Left)) {
    316 
    317     Drop      = TCP_SUB_SEQ (Left, Seg->Seq);
    318     Urg       = Seg->Seq + Seg->Urg;
    319     Seg->Seq  = Left;
    320 
    321     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
    322       TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);
    323       Drop--;
    324     }
    325 
    326     //
    327     // Adjust the urgent point
    328     //
    329     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG)) {
    330 
    331       if (TCP_SEQ_LT (Urg, Seg->Seq)) {
    332 
    333         TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);
    334       } else {
    335         Seg->Urg = (UINT16) TCP_SUB_SEQ (Urg, Seg->Seq);
    336       }
    337     }
    338 
    339     if (Drop != 0) {
    340       NetbufTrim (Nbuf, Drop, NET_BUF_HEAD);
    341     }
    342   }
    343 
    344   //
    345   // Adjust the buffer tail
    346   //
    347   if (TCP_SEQ_GT (Seg->End, Right)) {
    348 
    349     Drop      = TCP_SUB_SEQ (Seg->End, Right);
    350     Seg->End  = Right;
    351 
    352     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
    353       TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);
    354       Drop--;
    355     }
    356 
    357     if (Drop != 0) {
    358       NetbufTrim (Nbuf, Drop, NET_BUF_TAIL);
    359     }
    360   }
    361 
    362   ASSERT (TcpVerifySegment (Nbuf) != 0);
    363 }
    364 
    365 /**
    366   Trim off the data outside the tcb's receive window.
    367 
    368   @param[in]  Tcb      Pointer to the TCP_CB of this TCP instance.
    369   @param[in]  Nbuf     Pointer to the NET_BUF containing the received tcp segment.
    370 
    371 **/
    372 VOID
    373 TcpTrimInWnd (
    374   IN TCP_CB  *Tcb,
    375   IN NET_BUF *Nbuf
    376   )
    377 {
    378   TcpTrimSegment (Nbuf, Tcb->RcvNxt, Tcb->RcvWl2 + Tcb->RcvWnd);
    379 }
    380 
    381 /**
    382   Process the data and FIN flag, and check whether to deliver
    383   data to the socket layer.
    384 
    385   @param[in, out]  Tcb      Pointer to the TCP_CB of this TCP instance.
    386 
    387   @retval 0        No error occurred to deliver data.
    388   @retval -1       An error condition occurred. The proper response is to reset the
    389                    connection.
    390 
    391 **/
    392 INTN
    393 TcpDeliverData (
    394   IN OUT TCP_CB *Tcb
    395   )
    396 {
    397   LIST_ENTRY      *Entry;
    398   NET_BUF         *Nbuf;
    399   TCP_SEQNO       Seq;
    400   TCP_SEG         *Seg;
    401   UINT32          Urgent;
    402 
    403   ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));
    404 
    405   //
    406   // make sure there is some data queued,
    407   // and TCP is in a proper state
    408   //
    409   if (IsListEmpty (&Tcb->RcvQue) || !TCP_CONNECTED (Tcb->State)) {
    410 
    411     return 0;
    412   }
    413 
    414   //
    415   // Deliver data to the socket layer
    416   //
    417   Entry = Tcb->RcvQue.ForwardLink;
    418   Seq   = Tcb->RcvNxt;
    419 
    420   while (Entry != &Tcb->RcvQue) {
    421     Nbuf  = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
    422     Seg   = TCPSEG_NETBUF (Nbuf);
    423 
    424     ASSERT (TcpVerifySegment (Nbuf) != 0);
    425     ASSERT (Nbuf->Tcp == NULL);
    426 
    427     if (TCP_SEQ_GT (Seg->Seq, Seq)) {
    428       break;
    429     }
    430 
    431     Entry       = Entry->ForwardLink;
    432     Seq         = Seg->End;
    433     Tcb->RcvNxt = Seq;
    434 
    435     RemoveEntryList (&Nbuf->List);
    436 
    437     //
    438     // RFC793 Eighth step: process FIN in sequence
    439     //
    440     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
    441 
    442       //
    443       // The peer sends to us junky data after FIN,
    444       // reset the connection.
    445       //
    446       if (!IsListEmpty (&Tcb->RcvQue)) {
    447         DEBUG (
    448           (EFI_D_ERROR,
    449           "TcpDeliverData: data received after FIN from peer of TCB %p, reset connection\n",
    450           Tcb)
    451           );
    452 
    453         NetbufFree (Nbuf);
    454         return -1;
    455       }
    456 
    457       DEBUG (
    458         (EFI_D_INFO,
    459         "TcpDeliverData: processing FIN from peer of TCB %p\n",
    460         Tcb)
    461         );
    462 
    463       switch (Tcb->State) {
    464       case TCP_SYN_RCVD:
    465       case TCP_ESTABLISHED:
    466 
    467         TcpSetState (Tcb, TCP_CLOSE_WAIT);
    468         break;
    469 
    470       case TCP_FIN_WAIT_1:
    471 
    472         if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {
    473 
    474           TcpSetState (Tcb, TCP_CLOSING);
    475           break;
    476         }
    477 
    478       //
    479       // fall through
    480       //
    481       case TCP_FIN_WAIT_2:
    482 
    483         TcpSetState (Tcb, TCP_TIME_WAIT);
    484         TcpClearAllTimer (Tcb);
    485 
    486         if (Tcb->TimeWaitTimeout != 0) {
    487 
    488           TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);
    489         } else {
    490 
    491           DEBUG (
    492             (EFI_D_WARN,
    493             "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
    494             Tcb)
    495             );
    496 
    497           TcpSendAck (Tcb);
    498           TcpClose (Tcb);
    499         }
    500         break;
    501 
    502       case TCP_CLOSE_WAIT:
    503       case TCP_CLOSING:
    504       case TCP_LAST_ACK:
    505       case TCP_TIME_WAIT:
    506         //
    507         // The peer sends to us junk FIN byte. Discard
    508         // the buffer then reset the connection
    509         //
    510         NetbufFree (Nbuf);
    511         return -1;
    512         break;
    513       default:
    514         break;
    515       }
    516 
    517       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
    518 
    519       Seg->End--;
    520     }
    521 
    522     //
    523     // Don't delay the ack if PUSH flag is on.
    524     //
    525     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_PSH)) {
    526 
    527       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
    528     }
    529 
    530     if (Nbuf->TotalSize != 0) {
    531       Urgent = 0;
    532 
    533       if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&
    534           TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvUp))
    535       {
    536 
    537         if (TCP_SEQ_LEQ (Seg->End, Tcb->RcvUp)) {
    538           Urgent = Nbuf->TotalSize;
    539         } else {
    540           Urgent = TCP_SUB_SEQ (Tcb->RcvUp, Seg->Seq) + 1;
    541         }
    542       }
    543 
    544       SockDataRcvd (Tcb->Sk, Nbuf, Urgent);
    545     }
    546 
    547     if (TCP_FIN_RCVD (Tcb->State)) {
    548 
    549       SockNoMoreData (Tcb->Sk);
    550     }
    551 
    552     NetbufFree (Nbuf);
    553   }
    554 
    555   return 0;
    556 }
    557 
    558 /**
    559   Store the data into the reassemble queue.
    560 
    561   @param[in, out]  Tcb   Pointer to the TCP_CB of this TCP instance.
    562   @param[in]       Nbuf  Pointer to the buffer containing the data to be queued.
    563 
    564 **/
    565 VOID
    566 TcpQueueData (
    567   IN OUT TCP_CB  *Tcb,
    568   IN     NET_BUF *Nbuf
    569   )
    570 {
    571   TCP_SEG         *Seg;
    572   LIST_ENTRY      *Head;
    573   LIST_ENTRY      *Prev;
    574   LIST_ENTRY      *Cur;
    575   NET_BUF         *Node;
    576 
    577   ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));
    578 
    579   NET_GET_REF (Nbuf);
    580 
    581   Seg   = TCPSEG_NETBUF (Nbuf);
    582   Head  = &Tcb->RcvQue;
    583 
    584   //
    585   // Fast path to process normal case. That is,
    586   // no out-of-order segments are received.
    587   //
    588   if (IsListEmpty (Head)) {
    589 
    590     InsertTailList (Head, &Nbuf->List);
    591     return;
    592   }
    593 
    594   //
    595   // Find the point to insert the buffer
    596   //
    597   for (Prev = Head, Cur = Head->ForwardLink;
    598        Cur != Head;
    599        Prev = Cur, Cur = Cur->ForwardLink) {
    600 
    601     Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
    602 
    603     if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->Seq)) {
    604       break;
    605     }
    606   }
    607 
    608   //
    609   // Check whether the current segment overlaps with the
    610   // previous segment.
    611   //
    612   if (Prev != Head) {
    613     Node = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);
    614 
    615     if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->End)) {
    616 
    617       if (TCP_SEQ_LEQ (Seg->End, TCPSEG_NETBUF (Node)->End)) {
    618 
    619         NetbufFree (Nbuf);
    620         return;
    621       }
    622 
    623       TcpTrimSegment (Nbuf, TCPSEG_NETBUF (Node)->End, Seg->End);
    624     }
    625   }
    626 
    627   InsertHeadList (Prev, &Nbuf->List);
    628 
    629   TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
    630 
    631   //
    632   // Check the segments after the insert point.
    633   //
    634   while (Cur != Head) {
    635     Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
    636 
    637     if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->End, Seg->End)) {
    638 
    639       Cur = Cur->ForwardLink;
    640 
    641       RemoveEntryList (&Node->List);
    642       NetbufFree (Node);
    643       continue;
    644     }
    645 
    646     if (TCP_SEQ_LT (TCPSEG_NETBUF (Node)->Seq, Seg->End)) {
    647 
    648       if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->Seq, Seg->Seq)) {
    649 
    650         RemoveEntryList (&Nbuf->List);
    651         NetbufFree (Nbuf);
    652         return;
    653       }
    654 
    655       TcpTrimSegment (Nbuf, Seg->Seq, TCPSEG_NETBUF (Node)->Seq);
    656       break;
    657     }
    658 
    659     Cur = Cur->ForwardLink;
    660   }
    661 }
    662 
    663 
    664 /**
    665   Adjust the send queue or the retransmit queue.
    666 
    667   @param[in]  Tcb      Pointer to the TCP_CB of this TCP instance.
    668   @param[in]  Ack      The acknowledge seuqence number of the received segment.
    669 
    670 **/
    671 VOID
    672 TcpAdjustSndQue (
    673   IN TCP_CB    *Tcb,
    674   IN TCP_SEQNO Ack
    675   )
    676 {
    677   LIST_ENTRY      *Head;
    678   LIST_ENTRY      *Cur;
    679   NET_BUF         *Node;
    680   TCP_SEG         *Seg;
    681 
    682   Head  = &Tcb->SndQue;
    683   Cur   = Head->ForwardLink;
    684 
    685   while (Cur != Head) {
    686     Node  = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
    687     Seg   = TCPSEG_NETBUF (Node);
    688 
    689     if (TCP_SEQ_GEQ (Seg->Seq, Ack)) {
    690       break;
    691     }
    692 
    693     //
    694     // Remove completely ACKed segments
    695     //
    696     if (TCP_SEQ_LEQ (Seg->End, Ack)) {
    697       Cur = Cur->ForwardLink;
    698 
    699       RemoveEntryList (&Node->List);
    700       NetbufFree (Node);
    701       continue;
    702     }
    703 
    704     TcpTrimSegment (Node, Ack, Seg->End);
    705     break;
    706   }
    707 }
    708 
    709 /**
    710   Process the received TCP segments.
    711 
    712   @param[in]  Nbuf     Buffer that contains received a TCP segment without an IP header.
    713   @param[in]  Src      Source address of the segment, or the peer's IP address.
    714   @param[in]  Dst      Destination address of the segment, or the local end's IP
    715                        address.
    716   @param[in]  Version  IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
    717                        IP6 stack.
    718 
    719   @retval 0        Segment  processed successfully. It is either accepted or
    720                    discarded. However, no connection is reset by the segment.
    721   @retval -1       A connection is reset by the segment.
    722 
    723 **/
    724 INTN
    725 TcpInput (
    726   IN NET_BUF         *Nbuf,
    727   IN EFI_IP_ADDRESS  *Src,
    728   IN EFI_IP_ADDRESS  *Dst,
    729   IN UINT8           Version
    730   )
    731 {
    732   TCP_CB      *Tcb;
    733   TCP_CB      *Parent;
    734   TCP_OPTION  Option;
    735   TCP_HEAD    *Head;
    736   INT32       Len;
    737   TCP_SEG     *Seg;
    738   TCP_SEQNO   Right;
    739   TCP_SEQNO   Urg;
    740   UINT16      Checksum;
    741 
    742   ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));
    743 
    744   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
    745 
    746   Parent  = NULL;
    747   Tcb     = NULL;
    748 
    749   Head    = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);
    750   ASSERT (Head != NULL);
    751   Len     = Nbuf->TotalSize - (Head->HeadLen << 2);
    752 
    753   if ((Head->HeadLen < 5) || (Len < 0)) {
    754 
    755     DEBUG ((EFI_D_INFO, "TcpInput: received a malformed packet\n"));
    756     goto DISCARD;
    757   }
    758 
    759   if (Version == IP_VERSION_4) {
    760     Checksum = NetPseudoHeadChecksum (Src->Addr[0], Dst->Addr[0], 6, 0);
    761   } else {
    762     Checksum = NetIp6PseudoHeadChecksum (&Src->v6, &Dst->v6, 6, 0);
    763   }
    764 
    765   Checksum = TcpChecksum (Nbuf, Checksum);
    766 
    767   if (Checksum != 0) {
    768     DEBUG ((EFI_D_ERROR, "TcpInput: received a checksum error packet\n"));
    769     goto DISCARD;
    770   }
    771 
    772   if (TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)) {
    773     Len++;
    774   }
    775 
    776   if (TCP_FLG_ON (Head->Flag, TCP_FLG_FIN)) {
    777     Len++;
    778   }
    779 
    780   Tcb = TcpLocateTcb (
    781           Head->DstPort,
    782           Dst,
    783           Head->SrcPort,
    784           Src,
    785           Version,
    786           (BOOLEAN) TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)
    787           );
    788 
    789   if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {
    790     DEBUG ((EFI_D_INFO, "TcpInput: send reset because no TCB found\n"));
    791 
    792     Tcb = NULL;
    793     goto SEND_RESET;
    794   }
    795 
    796   Seg = TcpFormatNetbuf (Tcb, Nbuf);
    797 
    798   //
    799   // RFC1122 recommended reaction to illegal option
    800   // (in fact, an illegal option length) is reset.
    801   //
    802   if (TcpParseOption (Nbuf->Tcp, &Option) == -1) {
    803     DEBUG (
    804       (EFI_D_ERROR,
    805       "TcpInput: reset the peer because of malformed option for TCB %p\n",
    806       Tcb)
    807       );
    808 
    809     goto SEND_RESET;
    810   }
    811 
    812   //
    813   // From now on, the segment is headless
    814   //
    815   NetbufTrim (Nbuf, (Head->HeadLen << 2), NET_BUF_HEAD);
    816   Nbuf->Tcp = NULL;
    817 
    818   //
    819   // Process the segment in LISTEN state.
    820   //
    821   if (Tcb->State == TCP_LISTEN) {
    822     //
    823     // First step: Check RST
    824     //
    825     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
    826       DEBUG (
    827         (EFI_D_WARN,
    828         "TcpInput: discard a reset segment for TCB %p in listening\n",
    829         Tcb)
    830         );
    831 
    832       goto DISCARD;
    833     }
    834 
    835     //
    836     // Second step: Check ACK.
    837     // Any ACK sent to TCP in LISTEN is reseted.
    838     //
    839     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
    840       DEBUG (
    841         (EFI_D_WARN,
    842         "TcpInput: send reset because of segment with ACK for TCB %p in listening\n",
    843         Tcb)
    844         );
    845 
    846       goto SEND_RESET;
    847     }
    848 
    849     //
    850     // Third step: Check SYN
    851     //
    852     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
    853       //
    854       // create a child TCB to handle the data
    855       //
    856       Parent  = Tcb;
    857 
    858       Tcb     = TcpCloneTcb (Parent);
    859       if (Tcb == NULL) {
    860         DEBUG (
    861           (EFI_D_ERROR,
    862           "TcpInput: discard a segment because failed to clone a child for TCB %p\n",
    863           Tcb)
    864           );
    865 
    866         goto DISCARD;
    867       }
    868 
    869       DEBUG (
    870         (EFI_D_INFO,
    871         "TcpInput: create a child for TCB %p in listening\n",
    872         Tcb)
    873         );
    874 
    875       //
    876       // init the TCB structure
    877       //
    878       IP6_COPY_ADDRESS (&Tcb->LocalEnd.Ip, Dst);
    879       IP6_COPY_ADDRESS (&Tcb->RemoteEnd.Ip, Src);
    880       Tcb->LocalEnd.Port  = Head->DstPort;
    881       Tcb->RemoteEnd.Port = Head->SrcPort;
    882 
    883       TcpInitTcbLocal (Tcb);
    884       TcpInitTcbPeer (Tcb, Seg, &Option);
    885 
    886       TcpSetState (Tcb, TCP_SYN_RCVD);
    887       TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);
    888       TcpTrimInWnd (Tcb, Nbuf);
    889 
    890       goto StepSix;
    891     }
    892 
    893     goto DISCARD;
    894 
    895   } else if (Tcb->State == TCP_SYN_SENT) {
    896     //
    897     // First step: Check ACK bit
    898     //
    899     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK) && (Seg->Ack != Tcb->Iss + 1)) {
    900 
    901       DEBUG (
    902         (EFI_D_WARN,
    903         "TcpInput: send reset because of wrong ACK received for TCB %p in SYN_SENT\n",
    904         Tcb)
    905         );
    906 
    907       goto SEND_RESET;
    908     }
    909 
    910     //
    911     // Second step: Check RST bit
    912     //
    913     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
    914 
    915       if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
    916 
    917         DEBUG (
    918           (EFI_D_WARN,
    919           "TcpInput: connection reset by peer for TCB %p in SYN_SENT\n",
    920           Tcb)
    921           );
    922 
    923         SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);
    924         goto DROP_CONNECTION;
    925       } else {
    926 
    927         DEBUG (
    928           (EFI_D_WARN,
    929           "TcpInput: discard a reset segment because of no ACK for TCB %p in SYN_SENT\n",
    930           Tcb)
    931           );
    932 
    933         goto DISCARD;
    934       }
    935     }
    936 
    937     //
    938     // Third step: Check security and precedence. Skipped
    939     //
    940 
    941     //
    942     // Fourth step: Check SYN. Pay attention to simultaneous open
    943     //
    944     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
    945 
    946       TcpInitTcbPeer (Tcb, Seg, &Option);
    947 
    948       if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
    949 
    950         Tcb->SndUna = Seg->Ack;
    951       }
    952 
    953       TcpClearTimer (Tcb, TCP_TIMER_REXMIT);
    954 
    955       if (TCP_SEQ_GT (Tcb->SndUna, Tcb->Iss)) {
    956 
    957         TcpSetState (Tcb, TCP_ESTABLISHED);
    958 
    959         TcpClearTimer (Tcb, TCP_TIMER_CONNECT);
    960         TcpDeliverData (Tcb);
    961 
    962         if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&
    963             TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON))
    964         {
    965 
    966           TcpComputeRtt (Tcb, Tcb->RttMeasure);
    967           TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
    968         }
    969 
    970         TcpTrimInWnd (Tcb, Nbuf);
    971 
    972         TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
    973 
    974         DEBUG (
    975           (EFI_D_INFO,
    976           "TcpInput: connection established for TCB %p in SYN_SENT\n",
    977           Tcb)
    978           );
    979 
    980         goto StepSix;
    981       } else {
    982         //
    983         // Received a SYN segment without ACK, simultanous open.
    984         //
    985         TcpSetState (Tcb, TCP_SYN_RCVD);
    986 
    987         ASSERT (Tcb->SndNxt == Tcb->Iss + 1);
    988         TcpAdjustSndQue (Tcb, Tcb->SndNxt);
    989 
    990         TcpTrimInWnd (Tcb, Nbuf);
    991 
    992         DEBUG (
    993           (EFI_D_WARN,
    994           "TcpInput: simultaneous open for TCB %p in SYN_SENT\n",
    995           Tcb)
    996           );
    997 
    998         goto StepSix;
    999       }
   1000     }
   1001 
   1002     goto DISCARD;
   1003   }
   1004 
   1005   //
   1006   // Process segment in SYN_RCVD or TCP_CONNECTED states
   1007   //
   1008 
   1009   //
   1010   // Clear probe timer since the RecvWindow is opened.
   1011   //
   1012   if (Tcb->ProbeTimerOn && (Seg->Wnd != 0)) {
   1013     TcpClearTimer (Tcb, TCP_TIMER_PROBE);
   1014     Tcb->ProbeTimerOn = FALSE;
   1015   }
   1016 
   1017   //
   1018   // First step: Check whether SEG.SEQ is acceptable
   1019   //
   1020   if (TcpSeqAcceptable (Tcb, Seg) == 0) {
   1021     DEBUG (
   1022       (EFI_D_WARN,
   1023       "TcpInput: sequence acceptance test failed for segment of TCB %p\n",
   1024       Tcb)
   1025       );
   1026 
   1027     if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
   1028       TcpSendAck (Tcb);
   1029     }
   1030 
   1031     goto DISCARD;
   1032   }
   1033 
   1034   if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) &&
   1035       (Tcb->RcvWl2 == Seg->End) &&
   1036       !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN))
   1037   {
   1038 
   1039     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
   1040   }
   1041 
   1042   //
   1043   // Second step: Check the RST
   1044   //
   1045   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
   1046 
   1047     DEBUG ((EFI_D_WARN, "TcpInput: connection reset for TCB %p\n", Tcb));
   1048 
   1049     if (Tcb->State == TCP_SYN_RCVD) {
   1050 
   1051       SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_REFUSED);
   1052 
   1053       //
   1054       // This TCB comes from either a LISTEN TCB,
   1055       // or active open TCB with simultanous open.
   1056       // Do NOT signal user CONNECTION refused
   1057       // if it comes from a LISTEN TCB.
   1058       //
   1059     } else if ((Tcb->State == TCP_ESTABLISHED) ||
   1060                (Tcb->State == TCP_FIN_WAIT_1) ||
   1061                (Tcb->State == TCP_FIN_WAIT_2) ||
   1062                (Tcb->State == TCP_CLOSE_WAIT))
   1063     {
   1064 
   1065       SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);
   1066 
   1067     } else {
   1068     }
   1069 
   1070     goto DROP_CONNECTION;
   1071   }
   1072 
   1073   //
   1074   // Trim the data and flags.
   1075   //
   1076   TcpTrimInWnd (Tcb, Nbuf);
   1077 
   1078   //
   1079   // Third step: Check security and precedence, Ignored
   1080   //
   1081 
   1082   //
   1083   // Fourth step: Check the SYN bit.
   1084   //
   1085   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
   1086 
   1087     DEBUG (
   1088       (EFI_D_WARN,
   1089       "TcpInput: connection reset because received extra SYN for TCB %p\n",
   1090       Tcb)
   1091       );
   1092 
   1093     SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);
   1094     goto RESET_THEN_DROP;
   1095   }
   1096   //
   1097   // Fifth step: Check the ACK
   1098   //
   1099   if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
   1100     DEBUG (
   1101       (EFI_D_WARN,
   1102       "TcpInput: segment discard because of no ACK for connected TCB %p\n",
   1103       Tcb)
   1104       );
   1105 
   1106     goto DISCARD;
   1107   } else {
   1108     if (Tcb->IpInfo->IpVersion == IP_VERSION_6 && Tcb->Tick == 0) {
   1109       Tcp6RefreshNeighbor (Tcb, Src, TCP6_KEEP_NEIGHBOR_TIME * TICKS_PER_SECOND);
   1110       Tcb->Tick = TCP6_REFRESH_NEIGHBOR_TICK;
   1111     }
   1112   }
   1113 
   1114   if (Tcb->State == TCP_SYN_RCVD) {
   1115 
   1116     if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) &&
   1117         TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt))
   1118     {
   1119 
   1120       Tcb->SndWnd     = Seg->Wnd;
   1121       Tcb->SndWndMax  = MAX (Tcb->SndWnd, Tcb->SndWndMax);
   1122       Tcb->SndWl1     = Seg->Seq;
   1123       Tcb->SndWl2     = Seg->Ack;
   1124       TcpSetState (Tcb, TCP_ESTABLISHED);
   1125 
   1126       TcpClearTimer (Tcb, TCP_TIMER_CONNECT);
   1127       TcpDeliverData (Tcb);
   1128 
   1129       DEBUG (
   1130         (EFI_D_INFO,
   1131         "TcpInput: connection established for TCB %p in SYN_RCVD\n",
   1132         Tcb)
   1133         );
   1134 
   1135       //
   1136       // Continue the process as ESTABLISHED state
   1137       //
   1138     } else {
   1139       DEBUG (
   1140         (EFI_D_WARN,
   1141         "TcpInput: send reset because of wrong ACK for TCB %p in SYN_RCVD\n",
   1142         Tcb)
   1143         );
   1144 
   1145       goto SEND_RESET;
   1146     }
   1147   }
   1148 
   1149   if (TCP_SEQ_LT (Seg->Ack, Tcb->SndUna)) {
   1150 
   1151     DEBUG (
   1152       (EFI_D_WARN,
   1153       "TcpInput: ignore the out-of-data ACK for connected TCB %p\n",
   1154       Tcb)
   1155       );
   1156 
   1157     goto StepSix;
   1158 
   1159   } else if (TCP_SEQ_GT (Seg->Ack, Tcb->SndNxt)) {
   1160 
   1161     DEBUG (
   1162       (EFI_D_WARN,
   1163       "TcpInput: discard segment for future ACK for connected TCB %p\n",
   1164       Tcb)
   1165       );
   1166 
   1167     TcpSendAck (Tcb);
   1168     goto DISCARD;
   1169   }
   1170 
   1171   //
   1172   // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
   1173   //
   1174   if (TCP_FLG_ON (Option.Flag, TCP_OPTION_RCVD_TS)) {
   1175     //
   1176     // update TsRecent as specified in page 16 RFC1323.
   1177     // RcvWl2 equals to the variable "LastAckSent"
   1178     // defined there.
   1179     //
   1180     if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) &&
   1181         TCP_SEQ_LT (Tcb->RcvWl2, Seg->End))
   1182     {
   1183 
   1184       Tcb->TsRecent     = Option.TSVal;
   1185       Tcb->TsRecentAge  = mTcpTick;
   1186     }
   1187 
   1188     TcpComputeRtt (Tcb, TCP_SUB_TIME (mTcpTick, Option.TSEcr));
   1189 
   1190   } else if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {
   1191 
   1192     ASSERT (Tcb->CongestState == TCP_CONGEST_OPEN);
   1193 
   1194     TcpComputeRtt (Tcb, Tcb->RttMeasure);
   1195     TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
   1196   }
   1197 
   1198   if (Seg->Ack == Tcb->SndNxt) {
   1199 
   1200     TcpClearTimer (Tcb, TCP_TIMER_REXMIT);
   1201   } else {
   1202 
   1203     TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);
   1204   }
   1205 
   1206   //
   1207   // Count duplicate acks.
   1208   //
   1209   if ((Seg->Ack == Tcb->SndUna) &&
   1210       (Tcb->SndUna != Tcb->SndNxt) &&
   1211       (Seg->Wnd == Tcb->SndWnd) &&
   1212       (0 == Len))
   1213   {
   1214 
   1215     Tcb->DupAck++;
   1216   } else {
   1217 
   1218     Tcb->DupAck = 0;
   1219   }
   1220 
   1221   //
   1222   // Congestion avoidance, fast recovery and fast retransmission.
   1223   //
   1224   if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) ||
   1225       (Tcb->CongestState == TCP_CONGEST_LOSS))
   1226   {
   1227 
   1228     if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {
   1229 
   1230       if (Tcb->CWnd < Tcb->Ssthresh) {
   1231 
   1232         Tcb->CWnd += Tcb->SndMss;
   1233       } else {
   1234 
   1235         Tcb->CWnd += MAX (Tcb->SndMss * Tcb->SndMss / Tcb->CWnd, 1);
   1236       }
   1237 
   1238       Tcb->CWnd = MIN (Tcb->CWnd, TCP_MAX_WIN << Tcb->SndWndScale);
   1239     }
   1240 
   1241     if (Tcb->CongestState == TCP_CONGEST_LOSS) {
   1242       TcpFastLossRecover (Tcb, Seg);
   1243     }
   1244   } else {
   1245 
   1246     TcpFastRecover (Tcb, Seg);
   1247   }
   1248 
   1249   if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {
   1250 
   1251     TcpAdjustSndQue (Tcb, Seg->Ack);
   1252     Tcb->SndUna = Seg->Ack;
   1253 
   1254     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&
   1255         TCP_SEQ_LT (Tcb->SndUp, Seg->Ack))
   1256     {
   1257 
   1258       TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
   1259     }
   1260   }
   1261 
   1262   //
   1263   // Update window info
   1264   //
   1265   if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) ||
   1266       ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack)))
   1267   {
   1268 
   1269     Right = Seg->Ack + Seg->Wnd;
   1270 
   1271     if (TCP_SEQ_LT (Right, Tcb->SndWl2 + Tcb->SndWnd)) {
   1272 
   1273       if ((Tcb->SndWl1 == Seg->Seq) &&
   1274           (Tcb->SndWl2 == Seg->Ack) &&
   1275           (Len == 0))
   1276       {
   1277 
   1278         goto NO_UPDATE;
   1279       }
   1280 
   1281       DEBUG (
   1282         (EFI_D_WARN,
   1283         "TcpInput: peer shrinks the window for connected TCB %p\n",
   1284         Tcb)
   1285         );
   1286 
   1287       if ((Tcb->CongestState == TCP_CONGEST_RECOVER) &&
   1288           (TCP_SEQ_LT (Right, Tcb->Recover)))
   1289       {
   1290 
   1291         Tcb->Recover = Right;
   1292       }
   1293 
   1294       if ((Tcb->CongestState == TCP_CONGEST_LOSS) &&
   1295           (TCP_SEQ_LT (Right, Tcb->LossRecover)))
   1296       {
   1297 
   1298         Tcb->LossRecover = Right;
   1299       }
   1300 
   1301       if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {
   1302 
   1303         Tcb->SndNxt = Right;
   1304 
   1305         if (Right == Tcb->SndUna) {
   1306 
   1307           TcpClearTimer (Tcb, TCP_TIMER_REXMIT);
   1308           TcpSetProbeTimer (Tcb);
   1309         }
   1310       }
   1311     }
   1312 
   1313     Tcb->SndWnd     = Seg->Wnd;
   1314     Tcb->SndWndMax  = MAX (Tcb->SndWnd, Tcb->SndWndMax);
   1315     Tcb->SndWl1     = Seg->Seq;
   1316     Tcb->SndWl2     = Seg->Ack;
   1317   }
   1318 
   1319 NO_UPDATE:
   1320 
   1321   if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) &&
   1322       (Tcb->SndUna == Tcb->SndNxt))
   1323   {
   1324 
   1325     DEBUG (
   1326       (EFI_D_INFO,
   1327       "TcpInput: local FIN is ACKed by peer for connected TCB %p\n",
   1328       Tcb)
   1329       );
   1330 
   1331     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED);
   1332   }
   1333 
   1334   //
   1335   // Transit the state if proper.
   1336   //
   1337   switch (Tcb->State) {
   1338   case TCP_FIN_WAIT_1:
   1339 
   1340     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {
   1341 
   1342       TcpSetState (Tcb, TCP_FIN_WAIT_2);
   1343 
   1344       TcpClearAllTimer (Tcb);
   1345       TcpSetTimer (Tcb, TCP_TIMER_FINWAIT2, Tcb->FinWait2Timeout);
   1346     }
   1347 
   1348   case TCP_FIN_WAIT_2:
   1349 
   1350     break;
   1351 
   1352   case TCP_CLOSE_WAIT:
   1353     break;
   1354 
   1355   case TCP_CLOSING:
   1356 
   1357     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {
   1358 
   1359       TcpSetState (Tcb, TCP_TIME_WAIT);
   1360 
   1361       TcpClearAllTimer (Tcb);
   1362 
   1363       if (Tcb->TimeWaitTimeout != 0) {
   1364 
   1365         TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);
   1366       } else {
   1367 
   1368         DEBUG (
   1369           (EFI_D_WARN,
   1370           "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
   1371           Tcb)
   1372           );
   1373 
   1374         TcpClose (Tcb);
   1375       }
   1376     }
   1377     break;
   1378 
   1379   case TCP_LAST_ACK:
   1380 
   1381     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {
   1382 
   1383       TcpSetState (Tcb, TCP_CLOSED);
   1384     }
   1385 
   1386     break;
   1387 
   1388   case TCP_TIME_WAIT:
   1389 
   1390     TcpSendAck (Tcb);
   1391 
   1392     if (Tcb->TimeWaitTimeout != 0) {
   1393 
   1394       TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);
   1395     } else {
   1396 
   1397       DEBUG (
   1398         (EFI_D_WARN,
   1399         "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
   1400         Tcb)
   1401         );
   1402 
   1403       TcpClose (Tcb);
   1404     }
   1405     break;
   1406 
   1407   default:
   1408     break;
   1409   }
   1410   //
   1411   // Sixth step: Check the URG bit.update the Urg point
   1412   // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
   1413   //
   1414 StepSix:
   1415 
   1416   Tcb->Idle = 0;
   1417   TcpSetKeepaliveTimer (Tcb);
   1418 
   1419   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) && !TCP_FIN_RCVD (Tcb->State)) {
   1420 
   1421     DEBUG (
   1422       (EFI_D_INFO,
   1423       "TcpInput: received urgent data from peer for connected TCB %p\n",
   1424       Tcb)
   1425       );
   1426 
   1427     Urg = Seg->Seq + Seg->Urg;
   1428 
   1429     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&
   1430         TCP_SEQ_GT (Urg, Tcb->RcvUp))
   1431     {
   1432 
   1433       Tcb->RcvUp = Urg;
   1434     } else {
   1435 
   1436       Tcb->RcvUp = Urg;
   1437       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG);
   1438     }
   1439   }
   1440   //
   1441   // Seventh step: Process the segment data
   1442   //
   1443   if (Seg->End != Seg->Seq) {
   1444 
   1445     if (TCP_FIN_RCVD (Tcb->State)) {
   1446 
   1447       DEBUG (
   1448         (EFI_D_WARN,
   1449         "TcpInput: connection reset because data is lost for connected TCB %p\n",
   1450         Tcb)
   1451         );
   1452 
   1453       goto RESET_THEN_DROP;
   1454     }
   1455 
   1456     if (TCP_LOCAL_CLOSED (Tcb->State) && (Nbuf->TotalSize != 0)) {
   1457       DEBUG (
   1458         (EFI_D_WARN,
   1459         "TcpInput: connection reset because data is lost for connected TCB %p\n",
   1460         Tcb)
   1461         );
   1462 
   1463       goto RESET_THEN_DROP;
   1464     }
   1465 
   1466     TcpQueueData (Tcb, Nbuf);
   1467     if (TcpDeliverData (Tcb) == -1) {
   1468       goto RESET_THEN_DROP;
   1469     }
   1470 
   1471     if (!IsListEmpty (&Tcb->RcvQue)) {
   1472       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
   1473     }
   1474   }
   1475 
   1476   //
   1477   // Eighth step: check the FIN.
   1478   // This step is moved to TcpDeliverData. FIN will be
   1479   // processed in sequence there. Check the comments in
   1480   // the beginning of the file header for information.
   1481   //
   1482 
   1483   //
   1484   // Tcb is a new child of the listening Parent,
   1485   // commit it.
   1486   //
   1487   if (Parent != NULL) {
   1488     Tcb->Parent = Parent;
   1489     TcpInsertTcb (Tcb);
   1490   }
   1491 
   1492   if ((Tcb->State != TCP_CLOSED) &&
   1493       (TcpToSendData (Tcb, 0) == 0) &&
   1494       (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Nbuf->TotalSize != 0)))
   1495   {
   1496 
   1497     TcpToSendAck (Tcb);
   1498   }
   1499 
   1500   NetbufFree (Nbuf);
   1501   return 0;
   1502 
   1503 RESET_THEN_DROP:
   1504   TcpSendReset (Tcb, Head, Len, Dst, Src, Version);
   1505 
   1506 DROP_CONNECTION:
   1507   ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));
   1508 
   1509   NetbufFree (Nbuf);
   1510   TcpClose (Tcb);
   1511 
   1512   return -1;
   1513 
   1514 SEND_RESET:
   1515 
   1516   TcpSendReset (Tcb, Head, Len, Dst, Src, Version);
   1517 
   1518 DISCARD:
   1519 
   1520   //
   1521   // Tcb is a child of Parent, and it doesn't survive
   1522   //
   1523   DEBUG ((EFI_D_WARN, "TcpInput: Discard a packet\n"));
   1524   NetbufFree (Nbuf);
   1525 
   1526   if ((Parent != NULL) && (Tcb != NULL)) {
   1527 
   1528     ASSERT (Tcb->Sk != NULL);
   1529     TcpClose (Tcb);
   1530   }
   1531 
   1532   return 0;
   1533 }
   1534 
   1535 /**
   1536   Process the received ICMP error messages for TCP.
   1537 
   1538   @param[in]  Nbuf     The buffer that contains part of the TCP segment without an IP header
   1539                        truncated from the ICMP error packet.
   1540   @param[in]  IcmpErr  The ICMP error code interpreted from an ICMP error packet.
   1541   @param[in]  Src      Source address of the ICMP error message.
   1542   @param[in]  Dst      Destination address of the ICMP error message.
   1543   @param[in]  Version  IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
   1544                        IP6 stack.
   1545 
   1546 **/
   1547 VOID
   1548 TcpIcmpInput (
   1549   IN NET_BUF         *Nbuf,
   1550   IN UINT8           IcmpErr,
   1551   IN EFI_IP_ADDRESS  *Src,
   1552   IN EFI_IP_ADDRESS  *Dst,
   1553   IN UINT8           Version
   1554   )
   1555 {
   1556   TCP_HEAD         *Head;
   1557   TCP_CB           *Tcb;
   1558   TCP_SEQNO        Seq;
   1559   EFI_STATUS       IcmpErrStatus;
   1560   BOOLEAN          IcmpErrIsHard;
   1561   BOOLEAN          IcmpErrNotify;
   1562 
   1563   Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);
   1564   ASSERT (Head != NULL);
   1565 
   1566   Tcb = TcpLocateTcb (
   1567           Head->DstPort,
   1568           Dst,
   1569           Head->SrcPort,
   1570           Src,
   1571           Version,
   1572           FALSE
   1573           );
   1574   if (Tcb == NULL || Tcb->State == TCP_CLOSED) {
   1575 
   1576     goto CLEAN_EXIT;
   1577   }
   1578 
   1579   //
   1580   // Validate the sequence number.
   1581   //
   1582   Seq = NTOHL (Head->Seq);
   1583   if (!(TCP_SEQ_LEQ (Tcb->SndUna, Seq) && TCP_SEQ_LT (Seq, Tcb->SndNxt))) {
   1584 
   1585     goto CLEAN_EXIT;
   1586   }
   1587 
   1588   IcmpErrStatus = IpIoGetIcmpErrStatus (
   1589                     IcmpErr,
   1590                     Tcb->Sk->IpVersion,
   1591                     &IcmpErrIsHard,
   1592                     &IcmpErrNotify
   1593                     );
   1594 
   1595   if (IcmpErrNotify) {
   1596 
   1597     SOCK_ERROR (Tcb->Sk, IcmpErrStatus);
   1598   }
   1599 
   1600   if (IcmpErrIsHard) {
   1601 
   1602     TcpClose (Tcb);
   1603   }
   1604 
   1605 CLEAN_EXIT:
   1606 
   1607   NetbufFree (Nbuf);
   1608 }
   1609