From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/edk2/NetworkPkg/TcpDxe/TcpTimer.c | 587 +++++++++++++++++++++++++++++++++ 1 file changed, 587 insertions(+) create mode 100644 roms/edk2/NetworkPkg/TcpDxe/TcpTimer.c (limited to 'roms/edk2/NetworkPkg/TcpDxe/TcpTimer.c') diff --git a/roms/edk2/NetworkPkg/TcpDxe/TcpTimer.c b/roms/edk2/NetworkPkg/TcpDxe/TcpTimer.c new file mode 100644 index 000000000..106d9470d --- /dev/null +++ b/roms/edk2/NetworkPkg/TcpDxe/TcpTimer.c @@ -0,0 +1,587 @@ +/** @file + TCP timer related functions. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "TcpMain.h" + +UINT32 mTcpTick = 1000; + +/** + Connect timeout handler. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpConnectTimeout ( + IN OUT TCP_CB *Tcb + ); + +/** + Timeout handler for TCP retransmission timer. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpRexmitTimeout ( + IN OUT TCP_CB *Tcb + ); + +/** + Timeout handler for window probe timer. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpProbeTimeout ( + IN OUT TCP_CB *Tcb + ); + +/** + Timeout handler for keepalive timer. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpKeepaliveTimeout ( + IN OUT TCP_CB *Tcb + ); + +/** + Timeout handler for FIN_WAIT_2 timer. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpFinwait2Timeout ( + IN OUT TCP_CB *Tcb + ); + +/** + Timeout handler for 2MSL timer. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +Tcp2MSLTimeout ( + IN OUT TCP_CB *Tcb + ); + +TCP_TIMER_HANDLER mTcpTimerHandler[TCP_TIMER_NUMBER] = { + TcpConnectTimeout, + TcpRexmitTimeout, + TcpProbeTimeout, + TcpKeepaliveTimeout, + TcpFinwait2Timeout, + Tcp2MSLTimeout, +}; + +/** + Close the TCP connection. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpClose ( + IN OUT TCP_CB *Tcb + ) +{ + NetbufFreeList (&Tcb->SndQue); + NetbufFreeList (&Tcb->RcvQue); + + TcpSetState (Tcb, TCP_CLOSED); +} + +/** + Backoff the RTO. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpBackoffRto ( + IN OUT TCP_CB *Tcb + ) +{ + // + // Fold the RTT estimate if too many times, the estimate + // may be wrong, fold it. So the next time a valid + // measurement is sampled, we can start fresh. + // + if ((Tcb->LossTimes >= TCP_FOLD_RTT) && (Tcb->SRtt != 0)) { + Tcb->RttVar += Tcb->SRtt >> 2; + Tcb->SRtt = 0; + } + + Tcb->Rto <<= 1; + + if (Tcb->Rto < TCP_RTO_MIN) { + + Tcb->Rto = TCP_RTO_MIN; + } else if (Tcb->Rto > TCP_RTO_MAX) { + + Tcb->Rto = TCP_RTO_MAX; + } +} + +/** + Connect timeout handler. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpConnectTimeout ( + IN OUT TCP_CB *Tcb + ) +{ + if (!TCP_CONNECTED (Tcb->State)) { + DEBUG ( + (EFI_D_ERROR, + "TcpConnectTimeout: connection closed because connection timer timeout for TCB %p\n", + Tcb) + ); + + if (EFI_ABORTED == Tcb->Sk->SockError) { + SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT); + } + + if (TCP_SYN_RCVD == Tcb->State) { + DEBUG ( + (EFI_D_WARN, + "TcpConnectTimeout: send reset because connection timer timeout for TCB %p\n", + Tcb) + ); + + TcpResetConnection (Tcb); + + } + + TcpClose (Tcb); + } +} + + +/** + Timeout handler for TCP retransmission timer. + + @param[in, out] 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); +} + +/** + Timeout handler for window probe timer. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpProbeTimeout ( + IN OUT TCP_CB *Tcb + ) +{ + // + // This is the timer for sender's SWSA. RFC1122 requires + // a timer set for sender's SWSA, and suggest combine it + // with window probe timer. If data is sent, don't set + // the probe timer, since retransmit timer is on. + // + if ((TcpDataToSend (Tcb, 1) != 0) && (TcpToSendData (Tcb, 1) > 0)) { + + ASSERT (TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT) != 0); + Tcb->ProbeTimerOn = FALSE; + return ; + } + + TcpSendZeroProbe (Tcb); + TcpSetProbeTimer (Tcb); +} + +/** + Timeout handler for keepalive timer. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpKeepaliveTimeout ( + IN OUT TCP_CB *Tcb + ) +{ + Tcb->KeepAliveProbes++; + + // + // Too many Keep-alive probes, drop the connection + // + if (Tcb->KeepAliveProbes > Tcb->MaxKeepAlive) { + + if (EFI_ABORTED == Tcb->Sk->SockError) { + SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT); + } + + TcpClose (Tcb); + return ; + } + + TcpSendZeroProbe (Tcb); + TcpSetKeepaliveTimer (Tcb); +} + +/** + Timeout handler for FIN_WAIT_2 timer. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpFinwait2Timeout ( + IN OUT TCP_CB *Tcb + ) +{ + DEBUG ( + (EFI_D_WARN, + "TcpFinwait2Timeout: connection closed because FIN_WAIT2 timer timeouts for TCB %p\n", + Tcb) + ); + + TcpClose (Tcb); +} + +/** + Timeout handler for 2MSL timer. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +Tcp2MSLTimeout ( + IN OUT TCP_CB *Tcb + ) +{ + DEBUG ( + (EFI_D_WARN, + "Tcp2MSLTimeout: connection closed because TIME_WAIT timer timeouts for TCB %p\n", + Tcb) + ); + + TcpClose (Tcb); +} + +/** + Update the timer status and the next expire time according to the timers + to expire in a specific future time slot. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpUpdateTimer ( + IN OUT TCP_CB *Tcb + ) +{ + UINT16 Index; + + // + // Don't use a too large value to init NextExpire + // since mTcpTick wraps around as sequence no does. + // + Tcb->NextExpire = TCP_EXPIRE_TIME; + TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON); + + for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) { + + if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) && + TCP_TIME_LT (Tcb->Timer[Index], mTcpTick + Tcb->NextExpire) + ) { + + Tcb->NextExpire = TCP_SUB_TIME (Tcb->Timer[Index], mTcpTick); + TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON); + } + } +} + +/** + Enable a TCP timer. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + @param[in] Timer The index of the timer to be enabled. + @param[in] TimeOut The timeout value of this timer. + +**/ +VOID +TcpSetTimer ( + IN OUT TCP_CB *Tcb, + IN UINT16 Timer, + IN UINT32 TimeOut + ) +{ + TCP_SET_TIMER (Tcb->EnabledTimer, Timer); + Tcb->Timer[Timer] = mTcpTick + TimeOut; + + TcpUpdateTimer (Tcb); +} + +/** + Clear one TCP timer. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + @param[in] Timer The index of the timer to be cleared. + +**/ +VOID +TcpClearTimer ( + IN OUT TCP_CB *Tcb, + IN UINT16 Timer + ) +{ + TCP_CLEAR_TIMER (Tcb->EnabledTimer, Timer); + TcpUpdateTimer (Tcb); +} + +/** + Clear all TCP timers. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpClearAllTimer ( + IN OUT TCP_CB *Tcb + ) +{ + Tcb->EnabledTimer = 0; + TcpUpdateTimer (Tcb); +} + +/** + Enable the window prober timer and set the timeout value. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpSetProbeTimer ( + IN OUT TCP_CB *Tcb + ) +{ + if (!Tcb->ProbeTimerOn) { + Tcb->ProbeTime = Tcb->Rto; + Tcb->ProbeTimerOn = TRUE; + + } else { + Tcb->ProbeTime <<= 1; + } + + if (Tcb->ProbeTime < TCP_RTO_MIN) { + + Tcb->ProbeTime = TCP_RTO_MIN; + } else if (Tcb->ProbeTime > TCP_RTO_MAX) { + + Tcb->ProbeTime = TCP_RTO_MAX; + } + + TcpSetTimer (Tcb, TCP_TIMER_PROBE, Tcb->ProbeTime); +} + +/** + Enable the keepalive timer and set the timeout value. + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + +**/ +VOID +TcpSetKeepaliveTimer ( + IN OUT TCP_CB *Tcb + ) +{ + if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE)) { + return ; + + } + + // + // Set the timer to KeepAliveIdle if either + // 1. the keepalive timer is off + // 2. The keepalive timer is on, but the idle + // is less than KeepAliveIdle, that means the + // connection is alive since our last probe. + // + if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_KEEPALIVE) || + (Tcb->Idle < Tcb->KeepAliveIdle) + ) { + + TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAliveIdle); + Tcb->KeepAliveProbes = 0; + + } else { + + TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAlivePeriod); + } +} + +/** + Heart beat timer handler. + + @param[in] Context Context of the timer event, ignored. + +**/ +VOID +EFIAPI +TcpTickingDpc ( + IN VOID *Context + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + TCP_CB *Tcb; + INT16 Index; + + mTcpTick++; + mTcpGlobalIss += TCP_ISS_INCREMENT_2; + + // + // Don't use LIST_FOR_EACH, which isn't delete safe. + // + for (Entry = mTcpRunQue.ForwardLink; Entry != &mTcpRunQue; Entry = Next) { + + Next = Entry->ForwardLink; + + Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List); + + if (Tcb->State == TCP_CLOSED) { + continue; + } + // + // The connection is doing RTT measurement. + // + if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) { + Tcb->RttMeasure++; + } + + Tcb->Idle++; + + if (Tcb->DelayedAck != 0) { + TcpSendAck (Tcb); + } + + if (Tcb->IpInfo->IpVersion == IP_VERSION_6 && Tcb->Tick > 0) { + Tcb->Tick--; + } + + // + // No timer is active or no timer expired + // + if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON) || ((--Tcb->NextExpire) > 0)) { + + continue; + } + + // + // Call the timeout handler for each expired timer. + // + for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) { + + if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) && TCP_TIME_LEQ (Tcb->Timer[Index], mTcpTick)) { + // + // disable the timer before calling the handler + // in case the handler enables it again. + // + TCP_CLEAR_TIMER (Tcb->EnabledTimer, Index); + mTcpTimerHandler[Index](Tcb); + + // + // The Tcb may have been deleted by the timer, or + // no other timer is set. + // + if ((Next->BackLink != Entry) || (Tcb->EnabledTimer == 0)) { + break; + } + } + } + + // + // If the Tcb still exist or some timer is set, update the timer + // + if (Index == TCP_TIMER_NUMBER) { + TcpUpdateTimer (Tcb); + } + } +} + +/** + Heart beat timer handler, queues the DPC at TPL_CALLBACK. + + @param[in] Event Timer event signaled, ignored. + @param[in] Context Context of the timer event, ignored. + +**/ +VOID +EFIAPI +TcpTicking ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + QueueDpc (TPL_CALLBACK, TcpTickingDpc, Context); +} + -- cgit 1.2.3-korg