+++ /dev/null
-/** @file\r
- TCP timer related functions.\r
-\r
-Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php<BR>\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include "Tcp4Main.h"\r
-\r
-UINT32 mTcpTick = 1000;\r
-\r
-/**\r
- Connect timeout handler.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpConnectTimeout (\r
- IN OUT TCP_CB *Tcb\r
- );\r
-\r
-/**\r
- Timeout handler for TCP retransmission timer.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpRexmitTimeout (\r
- IN OUT TCP_CB *Tcb\r
- );\r
-\r
-/**\r
- Timeout handler for window probe timer.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpProbeTimeout (\r
- IN OUT TCP_CB *Tcb\r
- );\r
-\r
-/**\r
- Timeout handler for keepalive timer.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpKeepaliveTimeout (\r
- IN OUT TCP_CB *Tcb\r
- );\r
-\r
-/**\r
- Timeout handler for FIN_WAIT_2 timer.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpFinwait2Timeout (\r
- IN OUT TCP_CB *Tcb\r
- );\r
-\r
-/**\r
- Timeout handler for 2MSL timer.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-Tcp2MSLTimeout (\r
- IN OUT TCP_CB *Tcb\r
- );\r
-\r
-TCP_TIMER_HANDLER mTcpTimerHandler[TCP_TIMER_NUMBER] = {\r
- TcpConnectTimeout,\r
- TcpRexmitTimeout,\r
- TcpProbeTimeout,\r
- TcpKeepaliveTimeout,\r
- TcpFinwait2Timeout,\r
- Tcp2MSLTimeout,\r
-};\r
-\r
-/**\r
- Close the TCP connection.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpClose (\r
- IN OUT TCP_CB *Tcb\r
- )\r
-{\r
- NetbufFreeList (&Tcb->SndQue);\r
- NetbufFreeList (&Tcb->RcvQue);\r
-\r
- TcpSetState (Tcb, TCP_CLOSED);\r
-}\r
-\r
-\r
-/**\r
- Connect timeout handler.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpConnectTimeout (\r
- IN OUT TCP_CB *Tcb\r
- )\r
-{\r
- if (!TCP_CONNECTED (Tcb->State)) {\r
- DEBUG ((EFI_D_ERROR, "TcpConnectTimeout: connection closed "\r
- "because conenction timer timeout for TCB %p\n", Tcb));\r
-\r
- if (EFI_ABORTED == Tcb->Sk->SockError) {\r
- SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);\r
- }\r
-\r
- if (TCP_SYN_RCVD == Tcb->State) {\r
- DEBUG ((EFI_D_WARN, "TcpConnectTimeout: send reset because "\r
- "connection timer timeout for TCB %p\n", Tcb));\r
-\r
- TcpResetConnection (Tcb);\r
-\r
- }\r
-\r
- TcpClose (Tcb);\r
- }\r
-}\r
-\r
-\r
-/**\r
- Timeout handler for TCP retransmission timer.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpRexmitTimeout (\r
- IN OUT TCP_CB *Tcb\r
- )\r
-{\r
- UINT32 FlightSize;\r
-\r
- DEBUG ((EFI_D_WARN, "TcpRexmitTimeout: transmission "\r
- "timeout for TCB %p\n", Tcb));\r
-\r
- //\r
- // Set the congestion window. FlightSize is the\r
- // amount of data that has been sent but not\r
- // yet ACKed.\r
- //\r
- FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
- Tcb->Ssthresh = MAX ((UINT32) (2 * Tcb->SndMss), FlightSize / 2);\r
-\r
- Tcb->CWnd = Tcb->SndMss;\r
- Tcb->LossRecover = Tcb->SndNxt;\r
-\r
- Tcb->LossTimes++;\r
- if ((Tcb->LossTimes > Tcb->MaxRexmit) &&\r
- !TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_CONNECT)) {\r
-\r
- DEBUG ((EFI_D_ERROR, "TcpRexmitTimeout: connection closed "\r
- "because too many timeouts for TCB %p\n", Tcb));\r
-\r
- if (EFI_ABORTED == Tcb->Sk->SockError) {\r
- SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);\r
- }\r
-\r
- TcpClose (Tcb);\r
- return ;\r
- }\r
-\r
- TcpBackoffRto (Tcb);\r
- TcpRetransmit (Tcb, Tcb->SndUna);\r
- TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
-\r
- Tcb->CongestState = TCP_CONGEST_LOSS;\r
- TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
-}\r
-\r
-\r
-/**\r
- Timeout handler for window probe timer.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpProbeTimeout (\r
- IN OUT TCP_CB *Tcb\r
- )\r
-{\r
- //\r
- // This is the timer for sender's SWSA. RFC1122 requires\r
- // a timer set for sender's SWSA, and suggest combine it\r
- // with window probe timer. If data is sent, don't set\r
- // the probe timer, since retransmit timer is on.\r
- //\r
- if ((TcpDataToSend (Tcb, 1) != 0) && (TcpToSendData (Tcb, 1) > 0)) {\r
-\r
- ASSERT (TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT) != 0);\r
- Tcb->ProbeTimerOn = FALSE;\r
- return ;\r
- }\r
-\r
- TcpSendZeroProbe (Tcb);\r
- TcpSetProbeTimer (Tcb);\r
-}\r
-\r
-\r
-/**\r
- Timeout handler for keepalive timer.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpKeepaliveTimeout (\r
- IN OUT TCP_CB *Tcb\r
- )\r
-{\r
- Tcb->KeepAliveProbes++;\r
-\r
- //\r
- // Too many Keep-alive probes, drop the connection\r
- //\r
- if (Tcb->KeepAliveProbes > Tcb->MaxKeepAlive) {\r
-\r
- if (EFI_ABORTED == Tcb->Sk->SockError) {\r
- SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);\r
- }\r
-\r
- TcpClose (Tcb);\r
- return ;\r
- }\r
-\r
- TcpSendZeroProbe (Tcb);\r
- TcpSetKeepaliveTimer (Tcb);\r
-}\r
-\r
-\r
-/**\r
- Timeout handler for FIN_WAIT_2 timer.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpFinwait2Timeout (\r
- IN OUT TCP_CB *Tcb\r
- )\r
-{\r
- DEBUG ((EFI_D_WARN, "TcpFinwait2Timeout: connection closed "\r
- "because FIN_WAIT2 timer timeouts for TCB %p\n", Tcb));\r
-\r
- TcpClose (Tcb);\r
-}\r
-\r
-\r
-/**\r
- Timeout handler for 2MSL timer.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-Tcp2MSLTimeout (\r
- IN OUT TCP_CB *Tcb\r
- )\r
-{\r
- DEBUG ((EFI_D_WARN, "Tcp2MSLTimeout: connection closed "\r
- "because TIME_WAIT timer timeouts for TCB %p\n", Tcb));\r
-\r
- TcpClose (Tcb);\r
-}\r
-\r
-\r
-/**\r
- Update the timer status and the next expire time according to the timers\r
- to expire in a specific future time slot.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpUpdateTimer (\r
- IN OUT TCP_CB *Tcb\r
- )\r
-{\r
- UINT16 Index;\r
-\r
- //\r
- // Don't use a too large value to init NextExpire\r
- // since mTcpTick wraps around as sequence no does.\r
- //\r
- Tcb->NextExpire = 65535;\r
- TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);\r
-\r
- for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {\r
-\r
- if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&\r
- TCP_TIME_LT (Tcb->Timer[Index], mTcpTick + Tcb->NextExpire)) {\r
-\r
- Tcb->NextExpire = TCP_SUB_TIME (Tcb->Timer[Index], mTcpTick);\r
- TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);\r
- }\r
- }\r
-}\r
-\r
-\r
-/**\r
- Enable a TCP timer.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
- @param Timer The index of the timer to be enabled.\r
- @param TimeOut The timeout value of this timer.\r
-\r
-**/\r
-VOID\r
-TcpSetTimer (\r
- IN OUT TCP_CB *Tcb,\r
- IN UINT16 Timer,\r
- IN UINT32 TimeOut\r
- )\r
-{\r
- TCP_SET_TIMER (Tcb->EnabledTimer, Timer);\r
- Tcb->Timer[Timer] = mTcpTick + TimeOut;\r
-\r
- TcpUpdateTimer (Tcb);\r
-}\r
-\r
-\r
-/**\r
- Clear one TCP timer.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
- @param Timer The index of the timer to be cleared.\r
-\r
-**/\r
-VOID\r
-TcpClearTimer (\r
- IN OUT TCP_CB *Tcb,\r
- IN UINT16 Timer\r
- )\r
-{\r
- TCP_CLEAR_TIMER (Tcb->EnabledTimer, Timer);\r
- TcpUpdateTimer (Tcb);\r
-}\r
-\r
-\r
-/**\r
- Clear all TCP timers.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpClearAllTimer (\r
- IN OUT TCP_CB *Tcb\r
- )\r
-{\r
- Tcb->EnabledTimer = 0;\r
- TcpUpdateTimer (Tcb);\r
-}\r
-\r
-\r
-/**\r
- Enable the window prober timer and set the timeout value.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpSetProbeTimer (\r
- IN OUT TCP_CB *Tcb\r
- )\r
-{\r
- if (!Tcb->ProbeTimerOn) {\r
- Tcb->ProbeTime = Tcb->Rto;\r
- Tcb->ProbeTimerOn = TRUE;\r
-\r
- } else {\r
- Tcb->ProbeTime <<= 1;\r
- }\r
-\r
- if (Tcb->ProbeTime < TCP_RTO_MIN) {\r
-\r
- Tcb->ProbeTime = TCP_RTO_MIN;\r
- } else if (Tcb->ProbeTime > TCP_RTO_MAX) {\r
-\r
- Tcb->ProbeTime = TCP_RTO_MAX;\r
- }\r
-\r
- TcpSetTimer (Tcb, TCP_TIMER_PROBE, Tcb->ProbeTime);\r
-}\r
-\r
-\r
-/**\r
- Enable the keepalive timer and set the timeout value.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpSetKeepaliveTimer (\r
- IN OUT TCP_CB *Tcb\r
- )\r
-{\r
- if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE)) {\r
- return ;\r
-\r
- }\r
-\r
- //\r
- // Set the timer to KeepAliveIdle if either\r
- // 1. the keepalive timer is off\r
- // 2. The keepalive timer is on, but the idle\r
- // is less than KeepAliveIdle, that means the\r
- // connection is alive since our last probe.\r
- //\r
- if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_KEEPALIVE) ||\r
- (Tcb->Idle < Tcb->KeepAliveIdle)) {\r
-\r
- TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAliveIdle);\r
- Tcb->KeepAliveProbes = 0;\r
-\r
- } else {\r
-\r
- TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAlivePeriod);\r
- }\r
-}\r
-\r
-\r
-/**\r
- Backoff the RTO.\r
-\r
- @param Tcb Pointer to the TCP_CB of this TCP instance.\r
-\r
-**/\r
-VOID\r
-TcpBackoffRto (\r
- IN OUT TCP_CB *Tcb\r
- )\r
-{\r
- //\r
- // Fold the RTT estimate if too many times, the estimate\r
- // may be wrong, fold it. So the next time a valid\r
- // measurement is sampled, we can start fresh.\r
- //\r
- if ((Tcb->LossTimes >= TCP_FOLD_RTT) && (Tcb->SRtt != 0)) {\r
- Tcb->RttVar += Tcb->SRtt >> 2;\r
- Tcb->SRtt = 0;\r
- }\r
-\r
- Tcb->Rto <<= 1;\r
-\r
- if (Tcb->Rto < TCP_RTO_MIN) {\r
-\r
- Tcb->Rto = TCP_RTO_MIN;\r
- } else if (Tcb->Rto > TCP_RTO_MAX) {\r
-\r
- Tcb->Rto = TCP_RTO_MAX;\r
- }\r
-}\r
-\r
-\r
-/**\r
- Heart beat timer handler.\r
-\r
- @param Context Context of the timer event, ignored.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-TcpTickingDpc (\r
- IN VOID *Context\r
- )\r
-{\r
- LIST_ENTRY *Entry;\r
- LIST_ENTRY *Next;\r
- TCP_CB *Tcb;\r
- INT16 Index;\r
-\r
- mTcpTick++;\r
- mTcpGlobalIss += 100;\r
-\r
- //\r
- // Don't use LIST_FOR_EACH, which isn't delete safe.\r
- //\r
- for (Entry = mTcpRunQue.ForwardLink; Entry != &mTcpRunQue; Entry = Next) {\r
-\r
- Next = Entry->ForwardLink;\r
-\r
- Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
-\r
- if (Tcb->State == TCP_CLOSED) {\r
- continue;\r
- }\r
- //\r
- // The connection is doing RTT measurement.\r
- //\r
- if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
- Tcb->RttMeasure++;\r
- }\r
-\r
- Tcb->Idle++;\r
-\r
- if (Tcb->DelayedAck != 0) {\r
- TcpSendAck (Tcb);\r
- }\r
-\r
- //\r
- // No timer is active or no timer expired\r
- //\r
- if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON) ||\r
- ((--Tcb->NextExpire) > 0)) {\r
-\r
- continue;\r
- }\r
-\r
- //\r
- // Call the timeout handler for each expired timer.\r
- //\r
- for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {\r
-\r
- if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&\r
- TCP_TIME_LEQ (Tcb->Timer[Index], mTcpTick)) {\r
- //\r
- // disable the timer before calling the handler\r
- // in case the handler enables it again.\r
- //\r
- TCP_CLEAR_TIMER (Tcb->EnabledTimer, Index);\r
- mTcpTimerHandler[Index](Tcb);\r
-\r
- //\r
- // The Tcb may have been deleted by the timer, or\r
- // no other timer is set.\r
- //\r
- if ((Next->BackLink != Entry) ||\r
- (Tcb->EnabledTimer == 0)) {\r
- break;\r
- }\r
- }\r
- }\r
-\r
- //\r
- // If the Tcb still exist or some timer is set, update the timer\r
- //\r
- if (Index == TCP_TIMER_NUMBER) {\r
- TcpUpdateTimer (Tcb);\r
- }\r
- }\r
-}\r
-\r
-/**\r
- Heart beat timer handler, queues the DPC at TPL_CALLBACK.\r
-\r
- @param Event Timer event signaled, ignored.\r
- @param Context Context of the timer event, ignored.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-TcpTicking (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- QueueDpc (TPL_CALLBACK, TcpTickingDpc, Context);\r
-}\r
-\r