/** NewReno fast recovery, RFC3782. @param Tcb Pointer to the TCP_CB of this TCP instance. @param Seg Segment that triggers the fast recovery. **/ VOID TcpFastRecover ( IN OUT TCP_CB *Tcb, IN TCP_SEG *Seg ) { UINT32 FlightSize; UINT32 Acked; // // Step 1: Three duplicate ACKs and not in fast recovery // if (Tcb->CongestState != TCP_CONGEST_RECOVER) { // // Step 1A: Invoking fast retransmission. // FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna); Tcb->Ssthresh = MAX (FlightSize >> 1, (UINT32) (2 * Tcb->SndMss)); Tcb->Recover = Tcb->SndNxt; Tcb->CongestState = TCP_CONGEST_RECOVER; TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON); // // Step 2: Entering fast retransmission // TcpRetransmit (Tcb, Tcb->SndUna); Tcb->CWnd = Tcb->Ssthresh + 3 * Tcb->SndMss; DEBUG ((EFI_D_INFO, "TcpFastRecover: enter fast retransmission" " for TCB %p, recover point is %d\n", Tcb, Tcb->Recover)); return; }
/** Timeout handler for TCP retransmission timer. @param Tcb Pointer to the TCP_CB of this TCP instance. **/ VOID TcpRexmitTimeout ( IN OUT TCP_CB *Tcb ) { UINT32 FlightSize; DEBUG ((EFI_D_WARN, "TcpRexmitTimeout: transmission " "timeout for TCB %p\n", Tcb)); // // Set the congestion window. FlightSize is the // amount of data that has been sent but not // yet ACKed. // FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna); Tcb->Ssthresh = MAX ((UINT32) (2 * Tcb->SndMss), FlightSize / 2); Tcb->CWnd = Tcb->SndMss; Tcb->LossRecover = Tcb->SndNxt; Tcb->LossTimes++; if ((Tcb->LossTimes > Tcb->MaxRexmit) && !TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_CONNECT)) { DEBUG ((EFI_D_ERROR, "TcpRexmitTimeout: connection closed " "because too many timeouts for TCB %p\n", Tcb)); if (EFI_ABORTED == Tcb->Sk->SockError) { SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT); } TcpClose (Tcb); return ; } TcpBackoffRto (Tcb); TcpRetransmit (Tcb, Tcb->SndUna); TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto); Tcb->CongestState = TCP_CONGEST_LOSS; TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON); }