Home | History | Annotate | Download | only in TcpDxe
      1 /** @file
      2   TCP output process routines.
      3 
      4   Copyright (c) 2009 - 2010, 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 UINT8  mTcpOutFlag[] = {
     19   0,                          // TCP_CLOSED
     20   0,                          // TCP_LISTEN
     21   TCP_FLG_SYN,                // TCP_SYN_SENT
     22   TCP_FLG_SYN | TCP_FLG_ACK,  // TCP_SYN_RCVD
     23   TCP_FLG_ACK,                // TCP_ESTABLISHED
     24   TCP_FLG_FIN | TCP_FLG_ACK,  // TCP_FIN_WAIT_1
     25   TCP_FLG_ACK,                // TCP_FIN_WAIT_2
     26   TCP_FLG_ACK | TCP_FLG_FIN,  // TCP_CLOSING
     27   TCP_FLG_ACK,                // TCP_TIME_WAIT
     28   TCP_FLG_ACK,                // TCP_CLOSE_WAIT
     29   TCP_FLG_FIN | TCP_FLG_ACK   // TCP_LAST_ACK
     30 };
     31 
     32 /**
     33   Compute the sequence space left in the old receive window.
     34 
     35   @param[in]  Tcb     Pointer to the TCP_CB of this TCP instance.
     36 
     37   @return The sequence space left in the old receive window.
     38 
     39 **/
     40 UINT32
     41 TcpRcvWinOld (
     42   IN TCP_CB *Tcb
     43   )
     44 {
     45   UINT32  OldWin;
     46 
     47   OldWin = 0;
     48 
     49   if (TCP_SEQ_GT (Tcb->RcvWl2 + Tcb->RcvWnd, Tcb->RcvNxt)) {
     50 
     51     OldWin = TCP_SUB_SEQ (
     52               Tcb->RcvWl2 + Tcb->RcvWnd,
     53               Tcb->RcvNxt
     54               );
     55   }
     56 
     57   return OldWin;
     58 }
     59 
     60 /**
     61   Compute the current receive window.
     62 
     63   @param[in]  Tcb     Pointer to the TCP_CB of this TCP instance.
     64 
     65   @return The size of the current receive window, in bytes.
     66 
     67 **/
     68 UINT32
     69 TcpRcvWinNow (
     70   IN TCP_CB *Tcb
     71   )
     72 {
     73   SOCKET  *Sk;
     74   UINT32  Win;
     75   UINT32  Increase;
     76   UINT32  OldWin;
     77 
     78   Sk = Tcb->Sk;
     79   ASSERT (Sk != NULL);
     80 
     81   OldWin    = TcpRcvWinOld (Tcb);
     82 
     83   Win       = SockGetFreeSpace (Sk, SOCK_RCV_BUF);
     84 
     85   Increase  = 0;
     86   if (Win > OldWin) {
     87     Increase = Win - OldWin;
     88   }
     89 
     90   //
     91   // Receiver's SWS: don't advertise a bigger window
     92   // unless it can be increased by at least one Mss or
     93   // half of the receive buffer.
     94   //
     95   if ((Increase > Tcb->SndMss) || (2 * Increase >= GET_RCV_BUFFSIZE (Sk))) {
     96 
     97     return Win;
     98   }
     99 
    100   return OldWin;
    101 }
    102 
    103 /**
    104   Compute the value to fill in the window size field of the outgoing segment.
    105 
    106   @param[in, out]  Tcb     Pointer to the TCP_CB of this TCP instance.
    107   @param[in]       Syn     The flag to indicate whether the outgoing segment
    108                            is a SYN segment.
    109 
    110   @return The value of the local receive window size used to fill the outgoing segment.
    111 
    112 **/
    113 UINT16
    114 TcpComputeWnd (
    115   IN OUT TCP_CB  *Tcb,
    116   IN     BOOLEAN Syn
    117   )
    118 {
    119   UINT32  Wnd;
    120 
    121   //
    122   // RFC requires that initial window not be scaled
    123   //
    124   if (Syn) {
    125 
    126     Wnd = GET_RCV_BUFFSIZE (Tcb->Sk);
    127   } else {
    128 
    129     Wnd         = TcpRcvWinNow (Tcb);
    130 
    131     Tcb->RcvWnd = Wnd;
    132   }
    133 
    134   Wnd = MIN (Wnd >> Tcb->RcvWndScale, 0xffff);
    135   return NTOHS ((UINT16) Wnd);
    136 }
    137 
    138 /**
    139   Get the maximum SndNxt.
    140 
    141   @param[in]  Tcb     Pointer to the TCP_CB of this TCP instance.
    142 
    143   @return The sequence number of the maximum SndNxt.
    144 
    145 **/
    146 TCP_SEQNO
    147 TcpGetMaxSndNxt (
    148   IN TCP_CB *Tcb
    149   )
    150 {
    151   LIST_ENTRY      *Entry;
    152   NET_BUF         *Nbuf;
    153 
    154   if (IsListEmpty (&Tcb->SndQue)) {
    155     return Tcb->SndNxt;
    156   }
    157 
    158   Entry = Tcb->SndQue.BackLink;
    159   Nbuf  = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
    160 
    161   ASSERT (TCP_SEQ_GEQ (TCPSEG_NETBUF (Nbuf)->End, Tcb->SndNxt));
    162   return TCPSEG_NETBUF (Nbuf)->End;
    163 }
    164 
    165 /**
    166   Compute how much data to send.
    167 
    168   @param[in]  Tcb     Pointer to the TCP_CB of this TCP instance.
    169   @param[in]  Force   If TRUE, to ignore the sender's SWS avoidance algorithm and send
    170                       out data by force.
    171 
    172   @return The length of the data can be sent. If 0, no data can be sent.
    173 
    174 **/
    175 UINT32
    176 TcpDataToSend (
    177   IN TCP_CB *Tcb,
    178   IN INTN   Force
    179   )
    180 {
    181   SOCKET  *Sk;
    182   UINT32  Win;
    183   UINT32  Len;
    184   UINT32  Left;
    185   UINT32  Limit;
    186 
    187   Sk = Tcb->Sk;
    188   ASSERT (Sk != NULL);
    189 
    190   //
    191   // TCP should NOT send data beyond the send window
    192   // and congestion window. The right edge of send
    193   // window is defined as SND.WL2 + SND.WND. The right
    194   // edge of congestion window is defined as SND.UNA +
    195   // CWND.
    196   //
    197   Win   = 0;
    198   Limit = Tcb->SndWl2 + Tcb->SndWnd;
    199 
    200   if (TCP_SEQ_GT (Limit, Tcb->SndUna + Tcb->CWnd)) {
    201 
    202     Limit = Tcb->SndUna + Tcb->CWnd;
    203   }
    204 
    205   if (TCP_SEQ_GT (Limit, Tcb->SndNxt)) {
    206     Win = TCP_SUB_SEQ (Limit, Tcb->SndNxt);
    207   }
    208 
    209   //
    210   // The data to send contains two parts: the data on the
    211   // socket send queue, and the data on the TCB's send
    212   // buffer. The later can be non-zero if the peer shrinks
    213   // its advertised window.
    214   //
    215   Left  = GET_SND_DATASIZE (Sk) + TCP_SUB_SEQ (TcpGetMaxSndNxt (Tcb), Tcb->SndNxt);
    216 
    217   Len   = MIN (Win, Left);
    218 
    219   if (Len > Tcb->SndMss) {
    220     Len = Tcb->SndMss;
    221   }
    222 
    223   if ((Force != 0)|| (Len == 0 && Left == 0)) {
    224     return Len;
    225   }
    226 
    227   if (Len == 0 && Left != 0) {
    228     goto SetPersistTimer;
    229   }
    230 
    231   //
    232   // Sender's SWS avoidance: Don't send a small segment unless
    233   // a)A full-sized segment can be sent,
    234   // b)At least one-half of the maximum sized windows that
    235   // the other end has ever advertised.
    236   // c)It can send everything it has, and either it isn't
    237   // expecting an ACK, or the Nagle algorithm is disabled.
    238   //
    239   if ((Len == Tcb->SndMss) || (2 * Len >= Tcb->SndWndMax)) {
    240 
    241     return Len;
    242   }
    243 
    244   if ((Len == Left) &&
    245       ((Tcb->SndNxt == Tcb->SndUna) || TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE))
    246       ) {
    247 
    248     return Len;
    249   }
    250 
    251   //
    252   // RFC1122 suggests to set a timer when SWSA forbids TCP
    253   // sending more data, and combines it with a probe timer.
    254   //
    255 SetPersistTimer:
    256   if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) {
    257 
    258     DEBUG (
    259       (EFI_D_WARN,
    260       "TcpDataToSend: enter persistent state for TCB %p\n",
    261       Tcb)
    262       );
    263 
    264     if (!Tcb->ProbeTimerOn) {
    265       TcpSetProbeTimer (Tcb);
    266     }
    267   }
    268 
    269   return 0;
    270 }
    271 
    272 /**
    273   Build the TCP header of the TCP segment and transmit the segment by IP.
    274 
    275   @param[in, out]  Tcb     Pointer to the TCP_CB of this TCP instance.
    276   @param[in]       Nbuf    Pointer to the buffer containing the segment to be
    277                            sent out.
    278 
    279   @retval 0       The segment was sent out successfully.
    280   @retval -1      An error condition occurred.
    281 
    282 **/
    283 INTN
    284 TcpTransmitSegment (
    285   IN OUT TCP_CB  *Tcb,
    286   IN     NET_BUF *Nbuf
    287   )
    288 {
    289   UINT16    Len;
    290   TCP_HEAD  *Head;
    291   TCP_SEG   *Seg;
    292   BOOLEAN   Syn;
    293   UINT32    DataLen;
    294 
    295   ASSERT ((Nbuf != NULL) && (Nbuf->Tcp == NULL) && (TcpVerifySegment (Nbuf) != 0));
    296 
    297   DataLen = Nbuf->TotalSize;
    298 
    299   Seg     = TCPSEG_NETBUF (Nbuf);
    300   Syn     = TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN);
    301 
    302   if (Syn) {
    303 
    304     Len = TcpSynBuildOption (Tcb, Nbuf);
    305   } else {
    306 
    307     Len = TcpBuildOption (Tcb, Nbuf);
    308   }
    309 
    310   ASSERT ((Len % 4 == 0) && (Len <= 40));
    311 
    312   Len += sizeof (TCP_HEAD);
    313 
    314   Head = (TCP_HEAD *) NetbufAllocSpace (
    315                         Nbuf,
    316                         sizeof (TCP_HEAD),
    317                         NET_BUF_HEAD
    318                         );
    319 
    320   ASSERT (Head != NULL);
    321 
    322   Nbuf->Tcp       = Head;
    323 
    324   Head->SrcPort   = Tcb->LocalEnd.Port;
    325   Head->DstPort   = Tcb->RemoteEnd.Port;
    326   Head->Seq       = NTOHL (Seg->Seq);
    327   Head->Ack       = NTOHL (Tcb->RcvNxt);
    328   Head->HeadLen   = (UINT8) (Len >> 2);
    329   Head->Res       = 0;
    330   Head->Wnd       = TcpComputeWnd (Tcb, Syn);
    331   Head->Checksum  = 0;
    332 
    333   //
    334   // Check whether to set the PSH flag.
    335   //
    336   TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_PSH);
    337 
    338   if (DataLen != 0) {
    339     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_PSH) &&
    340         TCP_SEQ_BETWEEN (Seg->Seq, Tcb->SndPsh, Seg->End)
    341         ) {
    342 
    343       TCP_SET_FLG (Seg->Flag, TCP_FLG_PSH);
    344       TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);
    345 
    346     } else if ((Seg->End == Tcb->SndNxt) && (GET_SND_DATASIZE (Tcb->Sk) == 0)) {
    347 
    348       TCP_SET_FLG (Seg->Flag, TCP_FLG_PSH);
    349     }
    350   }
    351 
    352   //
    353   // Check whether to set the URG flag and the urgent pointer.
    354   //
    355   TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);
    356 
    357   if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) && TCP_SEQ_LEQ (Seg->Seq, Tcb->SndUp)) {
    358 
    359     TCP_SET_FLG (Seg->Flag, TCP_FLG_URG);
    360 
    361     if (TCP_SEQ_LT (Tcb->SndUp, Seg->End)) {
    362 
    363       Seg->Urg = (UINT16) TCP_SUB_SEQ (Tcb->SndUp, Seg->Seq);
    364     } else {
    365 
    366       Seg->Urg = (UINT16) MIN (
    367                             TCP_SUB_SEQ (Tcb->SndUp,
    368                             Seg->Seq),
    369                             0xffff
    370                             );
    371     }
    372   }
    373 
    374   Head->Flag      = Seg->Flag;
    375   Head->Urg       = NTOHS (Seg->Urg);
    376   Head->Checksum  = TcpChecksum (Nbuf, Tcb->HeadSum);
    377 
    378   //
    379   // Update the TCP session's control information.
    380   //
    381   Tcb->RcvWl2 = Tcb->RcvNxt;
    382   if (Syn) {
    383     Tcb->RcvWnd = NTOHS (Head->Wnd);
    384   }
    385 
    386   //
    387   // Clear the delayedack flag.
    388   //
    389   Tcb->DelayedAck = 0;
    390 
    391   return TcpSendIpPacket (Tcb, Nbuf, &Tcb->LocalEnd.Ip, &Tcb->RemoteEnd.Ip, Tcb->Sk->IpVersion);
    392 }
    393 
    394 /**
    395   Get a segment from the Tcb's SndQue.
    396 
    397   @param[in]  Tcb     Pointer to the TCP_CB of this TCP instance.
    398   @param[in]  Seq     The sequence number of the segment.
    399   @param[in]  Len     The maximum length of the segment.
    400 
    401   @return Pointer to the segment. If NULL, some error occurred.
    402 
    403 **/
    404 NET_BUF *
    405 TcpGetSegmentSndQue (
    406   IN TCP_CB    *Tcb,
    407   IN TCP_SEQNO Seq,
    408   IN UINT32    Len
    409   )
    410 {
    411   LIST_ENTRY      *Head;
    412   LIST_ENTRY      *Cur;
    413   NET_BUF         *Node;
    414   TCP_SEG         *Seg;
    415   NET_BUF         *Nbuf;
    416   TCP_SEQNO       End;
    417   UINT8           *Data;
    418   UINT8           Flag;
    419   INT32           Offset;
    420   INT32           CopyLen;
    421 
    422   ASSERT ((Tcb != NULL) && TCP_SEQ_LEQ (Seq, Tcb->SndNxt) && (Len > 0));
    423 
    424   //
    425   // Find the segment that contains the Seq.
    426   //
    427   Head  = &Tcb->SndQue;
    428 
    429   Node  = NULL;
    430   Seg   = NULL;
    431 
    432   NET_LIST_FOR_EACH (Cur, Head) {
    433     Node  = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
    434     Seg   = TCPSEG_NETBUF (Node);
    435 
    436     if (TCP_SEQ_LT (Seq, Seg->End) && TCP_SEQ_LEQ (Seg->Seq, Seq)) {
    437 
    438       break;
    439     }
    440   }
    441 
    442   if ((Cur == Head) || (Seg == NULL) || (Node == NULL)) {
    443     return NULL;
    444   }
    445 
    446   //
    447   // Return the buffer if it can be returned without
    448   // adjustment:
    449   //
    450   if ((Seg->Seq == Seq) &&
    451       TCP_SEQ_LEQ (Seg->End, Seg->Seq + Len) &&
    452       !NET_BUF_SHARED (Node)
    453       ) {
    454 
    455     NET_GET_REF (Node);
    456     return Node;
    457   }
    458 
    459   //
    460   // Create a new buffer and copy data there.
    461   //
    462   Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD);
    463 
    464   if (Nbuf == NULL) {
    465     return NULL;
    466   }
    467 
    468   NetbufReserve (Nbuf, TCP_MAX_HEAD);
    469 
    470   Flag  = Seg->Flag;
    471   End   = Seg->End;
    472 
    473   if (TCP_SEQ_LT (Seq + Len, Seg->End)) {
    474     End = Seq + Len;
    475   }
    476 
    477   CopyLen = TCP_SUB_SEQ (End, Seq);
    478   Offset  = TCP_SUB_SEQ (Seq, Seg->Seq);
    479 
    480   //
    481   // If SYN is set and out of the range, clear the flag.
    482   // Becuase the sequence of the first byte is SEG.SEQ+1,
    483   // adjust Offset by -1. If SYN is in the range, copy
    484   // one byte less.
    485   //
    486   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
    487 
    488     if (TCP_SEQ_LT (Seg->Seq, Seq)) {
    489 
    490       TCP_CLEAR_FLG (Flag, TCP_FLG_SYN);
    491       Offset--;
    492     } else {
    493 
    494       CopyLen--;
    495     }
    496   }
    497 
    498   //
    499   // If FIN is set and in the range, copy one byte less,
    500   // and if it is out of the range, clear the flag.
    501   //
    502   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
    503 
    504     if (Seg->End == End) {
    505 
    506       CopyLen--;
    507     } else {
    508 
    509       TCP_CLEAR_FLG (Flag, TCP_FLG_FIN);
    510     }
    511   }
    512 
    513   ASSERT (CopyLen >= 0);
    514 
    515   //
    516   // Copy data to the segment
    517   //
    518   if (CopyLen != 0) {
    519     Data = NetbufAllocSpace (Nbuf, CopyLen, NET_BUF_TAIL);
    520     ASSERT (Data != NULL);
    521 
    522     if ((INT32) NetbufCopy (Node, Offset, CopyLen, Data) != CopyLen) {
    523       goto OnError;
    524     }
    525   }
    526 
    527   CopyMem (TCPSEG_NETBUF (Nbuf), Seg, sizeof (TCP_SEG));
    528 
    529   TCPSEG_NETBUF (Nbuf)->Seq   = Seq;
    530   TCPSEG_NETBUF (Nbuf)->End   = End;
    531   TCPSEG_NETBUF (Nbuf)->Flag  = Flag;
    532 
    533   return Nbuf;
    534 
    535 OnError:
    536   NetbufFree (Nbuf);
    537   return NULL;
    538 }
    539 
    540 /**
    541   Get a segment from the Tcb's socket buffer.
    542 
    543   @param[in]  Tcb     Pointer to the TCP_CB of this TCP instance.
    544   @param[in]  Seq     The sequence number of the segment.
    545   @param[in]  Len     The maximum length of the segment.
    546 
    547   @return Pointer to the segment. If NULL, some error occurred.
    548 
    549 **/
    550 NET_BUF *
    551 TcpGetSegmentSock (
    552   IN TCP_CB    *Tcb,
    553   IN TCP_SEQNO Seq,
    554   IN UINT32    Len
    555   )
    556 {
    557   NET_BUF *Nbuf;
    558   UINT8   *Data;
    559   UINT32  DataGet;
    560 
    561   ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));
    562 
    563   Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD);
    564 
    565   if (Nbuf == NULL) {
    566     DEBUG (
    567       (EFI_D_ERROR,
    568       "TcpGetSegmentSock: failed to allocate a netbuf for TCB %p\n",
    569       Tcb)
    570       );
    571 
    572     return NULL;
    573   }
    574 
    575   NetbufReserve (Nbuf, TCP_MAX_HEAD);
    576 
    577   DataGet = 0;
    578 
    579   if (Len != 0) {
    580     //
    581     // copy data to the segment.
    582     //
    583     Data = NetbufAllocSpace (Nbuf, Len, NET_BUF_TAIL);
    584     ASSERT (Data != NULL);
    585 
    586     DataGet = SockGetDataToSend (Tcb->Sk, 0, Len, Data);
    587   }
    588 
    589   NET_GET_REF (Nbuf);
    590 
    591   TCPSEG_NETBUF (Nbuf)->Seq = Seq;
    592   TCPSEG_NETBUF (Nbuf)->End = Seq + Len;
    593 
    594   InsertTailList (&(Tcb->SndQue), &(Nbuf->List));
    595 
    596   if (DataGet != 0) {
    597 
    598     SockDataSent (Tcb->Sk, DataGet);
    599   }
    600 
    601   return Nbuf;
    602 }
    603 
    604 /**
    605   Get a segment starting from sequence Seq of a maximum
    606   length of Len.
    607 
    608   @param[in]  Tcb     Pointer to the TCP_CB of this TCP instance.
    609   @param[in]  Seq     The sequence number of the segment.
    610   @param[in]  Len     The maximum length of the segment.
    611 
    612   @return Pointer to the segment. If NULL, some error occurred.
    613 
    614 **/
    615 NET_BUF *
    616 TcpGetSegment (
    617   IN TCP_CB    *Tcb,
    618   IN TCP_SEQNO Seq,
    619   IN UINT32    Len
    620   )
    621 {
    622   NET_BUF *Nbuf;
    623 
    624   ASSERT (Tcb != NULL);
    625 
    626   //
    627   // Compare the SndNxt with the max sequence number sent.
    628   //
    629   if ((Len != 0) && TCP_SEQ_LT (Seq, TcpGetMaxSndNxt (Tcb))) {
    630 
    631     Nbuf = TcpGetSegmentSndQue (Tcb, Seq, Len);
    632   } else {
    633 
    634     Nbuf = TcpGetSegmentSock (Tcb, Seq, Len);
    635   }
    636 
    637   ASSERT (TcpVerifySegment (Nbuf) != 0);
    638   return Nbuf;
    639 }
    640 
    641 /**
    642   Retransmit the segment from sequence Seq.
    643 
    644   @param[in]  Tcb     Pointer to the TCP_CB of this TCP instance.
    645   @param[in]  Seq     The sequence number of the segment to be retransmitted.
    646 
    647   @retval 0       Retransmission succeeded.
    648   @retval -1      Error condition occurred.
    649 
    650 **/
    651 INTN
    652 TcpRetransmit (
    653   IN TCP_CB    *Tcb,
    654   IN TCP_SEQNO Seq
    655   )
    656 {
    657   NET_BUF *Nbuf;
    658   UINT32  Len;
    659 
    660   //
    661   // Compute the maxium length of retransmission. It is
    662   // limited by three factors:
    663   // 1. Less than SndMss
    664   // 2. Must in the current send window
    665   // 3. Will not change the boundaries of queued segments.
    666   //
    667   if (TCP_SEQ_LT (Tcb->SndWl2 + Tcb->SndWnd, Seq)) {
    668     DEBUG (
    669       (EFI_D_WARN,
    670       "TcpRetransmit: retransmission cancelled because send window too small for TCB %p\n",
    671       Tcb)
    672       );
    673 
    674     return 0;
    675   }
    676 
    677   Len   = TCP_SUB_SEQ (Tcb->SndWl2 + Tcb->SndWnd, Seq);
    678   Len   = MIN (Len, Tcb->SndMss);
    679 
    680   Nbuf  = TcpGetSegmentSndQue (Tcb, Seq, Len);
    681   if (Nbuf == NULL) {
    682     return -1;
    683   }
    684 
    685   ASSERT (TcpVerifySegment (Nbuf) != 0);
    686 
    687   if (TcpTransmitSegment (Tcb, Nbuf) != 0) {
    688     goto OnError;
    689   }
    690 
    691   //
    692   // The retransmitted buffer may be on the SndQue,
    693   // trim TCP head because all the buffers on SndQue
    694   // are headless.
    695   //
    696   ASSERT (Nbuf->Tcp != NULL);
    697   NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);
    698   Nbuf->Tcp = NULL;
    699 
    700   NetbufFree (Nbuf);
    701   return 0;
    702 
    703 OnError:
    704   if (Nbuf != NULL) {
    705     NetbufFree (Nbuf);
    706   }
    707 
    708   return -1;
    709 }
    710 
    711 /**
    712   Verify that all the segments in SndQue are in good shape.
    713 
    714   @param[in]  Head    Pointer to the head node of the SndQue.
    715 
    716   @retval     0       At least one segment is broken.
    717   @retval     1       All segments in the specific queue are in good shape.
    718 
    719 **/
    720 INTN
    721 TcpCheckSndQue (
    722   IN LIST_ENTRY     *Head
    723   )
    724 {
    725   LIST_ENTRY      *Entry;
    726   NET_BUF         *Nbuf;
    727   TCP_SEQNO       Seq;
    728 
    729   if (IsListEmpty (Head)) {
    730     return 1;
    731   }
    732   //
    733   // Initialize the Seq.
    734   //
    735   Entry = Head->ForwardLink;
    736   Nbuf  = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
    737   Seq   = TCPSEG_NETBUF (Nbuf)->Seq;
    738 
    739   NET_LIST_FOR_EACH (Entry, Head) {
    740     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
    741 
    742     if (TcpVerifySegment (Nbuf) == 0) {
    743       return 0;
    744     }
    745 
    746     //
    747     // All the node in the SndQue should has:
    748     // SEG.SEQ = LAST_SEG.END
    749     //
    750     if (Seq != TCPSEG_NETBUF (Nbuf)->Seq) {
    751       return 0;
    752     }
    753 
    754     Seq = TCPSEG_NETBUF (Nbuf)->End;
    755   }
    756 
    757   return 1;
    758 }
    759 
    760 /**
    761   Check whether to send data/SYN/FIN and piggyback an ACK.
    762 
    763   @param[in, out]  Tcb     Pointer to the TCP_CB of this TCP instance.
    764   @param[in]       Force   If TRUE, ignore the sender's SWS avoidance algorithm
    765                            and send out data by force.
    766 
    767   @return The number of bytes sent.
    768 
    769 **/
    770 INTN
    771 TcpToSendData (
    772   IN OUT TCP_CB *Tcb,
    773   IN     INTN   Force
    774   )
    775 {
    776   UINT32    Len;
    777   INTN      Sent;
    778   UINT8     Flag;
    779   NET_BUF   *Nbuf;
    780   TCP_SEG   *Seg;
    781   TCP_SEQNO Seq;
    782   TCP_SEQNO End;
    783 
    784   ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL) && (Tcb->State != TCP_LISTEN));
    785 
    786   Sent = 0;
    787 
    788   if ((Tcb->State == TCP_CLOSED) || TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT)) {
    789 
    790     return 0;
    791   }
    792 
    793   do {
    794     //
    795     // Compute how much data can be sent
    796     //
    797     Len   = TcpDataToSend (Tcb, Force);
    798     Seq   = Tcb->SndNxt;
    799 
    800     ASSERT ((Tcb->State) < (sizeof (mTcpOutFlag) / sizeof (mTcpOutFlag[0])));
    801     Flag  = mTcpOutFlag[Tcb->State];
    802 
    803     if ((Flag & TCP_FLG_SYN) != 0) {
    804 
    805       Seq = Tcb->Iss;
    806       Len = 0;
    807     }
    808 
    809     //
    810     // Only send a segment without data if SYN or
    811     // FIN is set.
    812     //
    813     if ((Len == 0) && ((Flag & (TCP_FLG_SYN | TCP_FLG_FIN)) == 0)) {
    814       return Sent;
    815     }
    816 
    817     Nbuf = TcpGetSegment (Tcb, Seq, Len);
    818 
    819     if (Nbuf == NULL) {
    820       DEBUG (
    821         (EFI_D_ERROR,
    822         "TcpToSendData: failed to get a segment for TCB %p\n",
    823         Tcb)
    824         );
    825 
    826       goto OnError;
    827     }
    828 
    829     Seg = TCPSEG_NETBUF (Nbuf);
    830 
    831     //
    832     // Set the TcpSeg in Nbuf.
    833     //
    834     Len = Nbuf->TotalSize;
    835     End = Seq + Len;
    836     if (TCP_FLG_ON (Flag, TCP_FLG_SYN)) {
    837       End++;
    838     }
    839 
    840     if ((Flag & TCP_FLG_FIN) != 0) {
    841       //
    842       // Send FIN if all data is sent, and FIN is
    843       // in the window
    844       //
    845       if ((TcpGetMaxSndNxt (Tcb) == Tcb->SndNxt) &&
    846           (GET_SND_DATASIZE (Tcb->Sk) == 0) &&
    847           TCP_SEQ_LT (End + 1, Tcb->SndWnd + Tcb->SndWl2)
    848             ) {
    849         DEBUG (
    850           (EFI_D_INFO,
    851           "TcpToSendData: send FIN to peer for TCB %p in state %s\n",
    852           Tcb,
    853           mTcpStateName[Tcb->State])
    854           );
    855 
    856         End++;
    857       } else {
    858         TCP_CLEAR_FLG (Flag, TCP_FLG_FIN);
    859       }
    860     }
    861 
    862     Seg->Seq  = Seq;
    863     Seg->End  = End;
    864     Seg->Flag = Flag;
    865 
    866     ASSERT (TcpVerifySegment (Nbuf) != 0);
    867     ASSERT (TcpCheckSndQue (&Tcb->SndQue) != 0);
    868 
    869     //
    870     // Don't send an empty segment here.
    871     //
    872     if (Seg->End == Seg->Seq) {
    873       DEBUG (
    874         (EFI_D_WARN,
    875         "TcpToSendData: created a empty segment for TCB %p, free it now\n",
    876         Tcb)
    877         );
    878 
    879       NetbufFree (Nbuf);
    880       return Sent;
    881     }
    882 
    883     if (TcpTransmitSegment (Tcb, Nbuf) != 0) {
    884       NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);
    885       Nbuf->Tcp = NULL;
    886 
    887       if ((Flag & TCP_FLG_FIN) != 0)  {
    888         TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);
    889       }
    890 
    891       goto OnError;
    892     }
    893 
    894     Sent += TCP_SUB_SEQ (End, Seq);
    895 
    896     //
    897     // All the buffers in the SndQue are headless.
    898     //
    899     ASSERT (Nbuf->Tcp != NULL);
    900 
    901     NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);
    902     Nbuf->Tcp = NULL;
    903 
    904     NetbufFree (Nbuf);
    905 
    906     //
    907     // Update the status in TCB.
    908     //
    909     Tcb->DelayedAck = 0;
    910 
    911     if ((Flag & TCP_FLG_FIN) != 0) {
    912       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);
    913     }
    914 
    915     if (TCP_SEQ_GT (End, Tcb->SndNxt)) {
    916       Tcb->SndNxt = End;
    917     }
    918 
    919     if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) {
    920       TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);
    921     }
    922 
    923     //
    924     // Enable RTT measurement only if not in retransmit.
    925     // Karn's algorithm requires not to update RTT when in loss.
    926     //
    927     if ((Tcb->CongestState == TCP_CONGEST_OPEN) && !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {
    928 
    929       DEBUG (
    930         (EFI_D_INFO,
    931         "TcpToSendData: set RTT measure sequence %d for TCB %p\n",
    932         Seq,
    933         Tcb)
    934         );
    935 
    936       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
    937       Tcb->RttSeq     = Seq;
    938       Tcb->RttMeasure = 0;
    939     }
    940 
    941   } while (Len == Tcb->SndMss);
    942 
    943   return Sent;
    944 
    945 OnError:
    946   if (Nbuf != NULL) {
    947     NetbufFree (Nbuf);
    948   }
    949 
    950   return Sent;
    951 }
    952 
    953 /**
    954   Send an ACK immediately.
    955 
    956   @param[in, out]  Tcb     Pointer to the TCP_CB of this TCP instance.
    957 
    958 **/
    959 VOID
    960 TcpSendAck (
    961   IN OUT TCP_CB *Tcb
    962   )
    963 {
    964   NET_BUF *Nbuf;
    965   TCP_SEG *Seg;
    966 
    967   Nbuf = NetbufAlloc (TCP_MAX_HEAD);
    968 
    969   if (Nbuf == NULL) {
    970     return;
    971   }
    972 
    973   NetbufReserve (Nbuf, TCP_MAX_HEAD);
    974 
    975   Seg       = TCPSEG_NETBUF (Nbuf);
    976   Seg->Seq  = Tcb->SndNxt;
    977   Seg->End  = Tcb->SndNxt;
    978   Seg->Flag = TCP_FLG_ACK;
    979 
    980   if (TcpTransmitSegment (Tcb, Nbuf) == 0) {
    981     TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
    982     Tcb->DelayedAck = 0;
    983   }
    984 
    985   NetbufFree (Nbuf);
    986 }
    987 
    988 /**
    989   Send a zero probe segment. It can be used by keepalive and zero window probe.
    990 
    991   @param[in, out]  Tcb     Pointer to the TCP_CB of this TCP instance.
    992 
    993   @retval 0       The zero probe segment was sent out successfully.
    994   @retval other   An error condition occurred.
    995 
    996 **/
    997 INTN
    998 TcpSendZeroProbe (
    999   IN OUT TCP_CB *Tcb
   1000   )
   1001 {
   1002   NET_BUF *Nbuf;
   1003   TCP_SEG *Seg;
   1004   INTN     Result;
   1005 
   1006   Nbuf = NetbufAlloc (TCP_MAX_HEAD);
   1007 
   1008   if (Nbuf == NULL) {
   1009     return -1;
   1010   }
   1011 
   1012   NetbufReserve (Nbuf, TCP_MAX_HEAD);
   1013 
   1014   //
   1015   // SndNxt-1 is out of window. The peer should respond
   1016   // with an ACK.
   1017   //
   1018   Seg       = TCPSEG_NETBUF (Nbuf);
   1019   Seg->Seq  = Tcb->SndNxt - 1;
   1020   Seg->End  = Tcb->SndNxt - 1;
   1021   Seg->Flag = TCP_FLG_ACK;
   1022 
   1023   Result    = TcpTransmitSegment (Tcb, Nbuf);
   1024   NetbufFree (Nbuf);
   1025 
   1026   return Result;
   1027 }
   1028 
   1029 /**
   1030   Check whether to send an ACK or delayed ACK.
   1031 
   1032   @param[in, out]  Tcb     Pointer to the TCP_CB of this TCP instance.
   1033 
   1034 **/
   1035 VOID
   1036 TcpToSendAck (
   1037   IN OUT TCP_CB *Tcb
   1038   )
   1039 {
   1040   UINT32 TcpNow;
   1041 
   1042   //
   1043   // Generally, TCP should send a delayed ACK unless:
   1044   //   1. ACK at least every other FULL sized segment received.
   1045   //   2. Packets received out of order.
   1046   //   3. Receiving window is open.
   1047   //
   1048   if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Tcb->DelayedAck >= 1)) {
   1049     TcpSendAck (Tcb);
   1050     return;
   1051   }
   1052 
   1053   TcpNow = TcpRcvWinNow (Tcb);
   1054 
   1055   if (TcpNow > TcpRcvWinOld (Tcb)) {
   1056     TcpSendAck (Tcb);
   1057     return;
   1058   }
   1059 
   1060   DEBUG (
   1061     (EFI_D_INFO,
   1062     "TcpToSendAck: scheduled a delayed ACK for TCB %p\n",
   1063     Tcb)
   1064     );
   1065 
   1066   //
   1067   // Schedule a delayed ACK.
   1068   //
   1069   Tcb->DelayedAck++;
   1070 }
   1071 
   1072 /**
   1073   Send a RESET segment in response to the segment received.
   1074 
   1075   @param[in]  Tcb     Pointer to the TCP_CB of this TCP instance. May be NULL.
   1076   @param[in]  Head    TCP header of the segment that triggers the reset.
   1077   @param[in]  Len     Length of the segment that triggers the reset.
   1078   @param[in]  Local   Local IP address.
   1079   @param[in]  Remote  Remote peer's IP address.
   1080   @param[in]  Version IP_VERSION_4 indicates TCP is running on IP4 stack,
   1081                       IP_VERSION_6 indicates TCP is running on IP6 stack.
   1082 
   1083   @retval     0       A reset was sent or there is no need to send it.
   1084   @retval     -1      No reset is sent.
   1085 
   1086 **/
   1087 INTN
   1088 TcpSendReset (
   1089   IN TCP_CB          *Tcb,
   1090   IN TCP_HEAD        *Head,
   1091   IN INT32           Len,
   1092   IN EFI_IP_ADDRESS  *Local,
   1093   IN EFI_IP_ADDRESS  *Remote,
   1094   IN UINT8           Version
   1095   )
   1096 {
   1097   NET_BUF   *Nbuf;
   1098   TCP_HEAD  *Nhead;
   1099   UINT16    HeadSum;
   1100 
   1101   //
   1102   // Don't respond to a Reset with reset.
   1103   //
   1104   if ((Head->Flag & TCP_FLG_RST) != 0) {
   1105     return 0;
   1106   }
   1107 
   1108   Nbuf = NetbufAlloc (TCP_MAX_HEAD);
   1109 
   1110   if (Nbuf == NULL) {
   1111     return -1;
   1112   }
   1113 
   1114   Nhead = (TCP_HEAD *) NetbufAllocSpace (
   1115                         Nbuf,
   1116                         sizeof (TCP_HEAD),
   1117                         NET_BUF_TAIL
   1118                         );
   1119 
   1120   ASSERT (Nhead != NULL);
   1121 
   1122   Nbuf->Tcp   = Nhead;
   1123   Nhead->Flag = TCP_FLG_RST;
   1124 
   1125   //
   1126   // Derive Seq/ACK from the segment if no TCB
   1127   // is associated with it, otherwise derive from the Tcb.
   1128   //
   1129   if (Tcb == NULL) {
   1130 
   1131     if (TCP_FLG_ON (Head->Flag, TCP_FLG_ACK)) {
   1132       Nhead->Seq  = Head->Ack;
   1133       Nhead->Ack  = 0;
   1134     } else {
   1135       Nhead->Seq = 0;
   1136       TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);
   1137       Nhead->Ack = HTONL (NTOHL (Head->Seq) + Len);
   1138     }
   1139   } else {
   1140 
   1141     Nhead->Seq  = HTONL (Tcb->SndNxt);
   1142     Nhead->Ack  = HTONL (Tcb->RcvNxt);
   1143     TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);
   1144   }
   1145 
   1146   Nhead->SrcPort  = Head->DstPort;
   1147   Nhead->DstPort  = Head->SrcPort;
   1148   Nhead->HeadLen  = (UINT8) (sizeof (TCP_HEAD) >> 2);
   1149   Nhead->Res      = 0;
   1150   Nhead->Wnd      = HTONS (0xFFFF);
   1151   Nhead->Checksum = 0;
   1152   Nhead->Urg      = 0;
   1153 
   1154   if (Version == IP_VERSION_4) {
   1155     HeadSum = NetPseudoHeadChecksum (Local->Addr[0], Remote->Addr[0], 6, 0);
   1156   } else {
   1157     HeadSum = NetIp6PseudoHeadChecksum (&Local->v6, &Remote->v6, 6, 0);
   1158   }
   1159 
   1160   Nhead->Checksum = TcpChecksum (Nbuf, HeadSum);
   1161 
   1162   TcpSendIpPacket (Tcb, Nbuf, Local, Remote, Version);
   1163 
   1164   NetbufFree (Nbuf);
   1165 
   1166   return 0;
   1167 }
   1168 
   1169 /**
   1170   Verify that the segment is in good shape.
   1171 
   1172   @param[in]  Nbuf    The buffer that contains the segment to be checked.
   1173 
   1174   @retval     0       The segment is broken.
   1175   @retval     1       The segment is in good shape.
   1176 
   1177 **/
   1178 INTN
   1179 TcpVerifySegment (
   1180   IN NET_BUF *Nbuf
   1181   )
   1182 {
   1183   TCP_HEAD  *Head;
   1184   TCP_SEG   *Seg;
   1185   UINT32    Len;
   1186 
   1187   if (Nbuf == NULL) {
   1188     return 1;
   1189   }
   1190 
   1191   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
   1192 
   1193   Seg   = TCPSEG_NETBUF (Nbuf);
   1194   Len   = Nbuf->TotalSize;
   1195   Head  = Nbuf->Tcp;
   1196 
   1197   if (Head != NULL) {
   1198     if (Head->Flag != Seg->Flag) {
   1199       return 0;
   1200     }
   1201 
   1202     Len -= (Head->HeadLen << 2);
   1203   }
   1204 
   1205   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
   1206     Len++;
   1207   }
   1208 
   1209   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
   1210     Len++;
   1211   }
   1212 
   1213   if (Seg->Seq + Len != Seg->End) {
   1214     return 0;
   1215   }
   1216 
   1217   return 1;
   1218 }
   1219 
   1220