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