VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/TcpDxe/TcpTimer.c

Last change on this file was 105670, checked in by vboxsync, 7 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 11.1 KB
Line 
1/** @file
2 TCP timer related functions.
3
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) Microsoft Corporation
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "TcpMain.h"
11
12UINT32 mTcpTick = 1000;
13
14/**
15 Connect timeout handler.
16
17 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
18
19**/
20VOID
21TcpConnectTimeout (
22 IN OUT TCP_CB *Tcb
23 );
24
25/**
26 Timeout handler for TCP retransmission timer.
27
28 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
29
30**/
31VOID
32TcpRexmitTimeout (
33 IN OUT TCP_CB *Tcb
34 );
35
36/**
37 Timeout handler for window probe timer.
38
39 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
40
41**/
42VOID
43TcpProbeTimeout (
44 IN OUT TCP_CB *Tcb
45 );
46
47/**
48 Timeout handler for keepalive timer.
49
50 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
51
52**/
53VOID
54TcpKeepaliveTimeout (
55 IN OUT TCP_CB *Tcb
56 );
57
58/**
59 Timeout handler for FIN_WAIT_2 timer.
60
61 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
62
63**/
64VOID
65TcpFinwait2Timeout (
66 IN OUT TCP_CB *Tcb
67 );
68
69/**
70 Timeout handler for 2MSL timer.
71
72 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
73
74**/
75VOID
76Tcp2MSLTimeout (
77 IN OUT TCP_CB *Tcb
78 );
79
80TCP_TIMER_HANDLER mTcpTimerHandler[TCP_TIMER_NUMBER] = {
81 TcpConnectTimeout,
82 TcpRexmitTimeout,
83 TcpProbeTimeout,
84 TcpKeepaliveTimeout,
85 TcpFinwait2Timeout,
86 Tcp2MSLTimeout,
87};
88
89/**
90 Close the TCP connection.
91
92 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
93
94**/
95VOID
96TcpClose (
97 IN OUT TCP_CB *Tcb
98 )
99{
100 NetbufFreeList (&Tcb->SndQue);
101 NetbufFreeList (&Tcb->RcvQue);
102
103 TcpSetState (Tcb, TCP_CLOSED);
104}
105
106/**
107 Backoff the RTO.
108
109 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
110
111**/
112VOID
113TcpBackoffRto (
114 IN OUT TCP_CB *Tcb
115 )
116{
117 //
118 // Fold the RTT estimate if too many times, the estimate
119 // may be wrong, fold it. So the next time a valid
120 // measurement is sampled, we can start fresh.
121 //
122 if ((Tcb->LossTimes >= TCP_FOLD_RTT) && (Tcb->SRtt != 0)) {
123 Tcb->RttVar += Tcb->SRtt >> 2;
124 Tcb->SRtt = 0;
125 }
126
127 Tcb->Rto <<= 1;
128
129 if (Tcb->Rto < TCP_RTO_MIN) {
130 Tcb->Rto = TCP_RTO_MIN;
131 } else if (Tcb->Rto > TCP_RTO_MAX) {
132 Tcb->Rto = TCP_RTO_MAX;
133 }
134}
135
136/**
137 Connect timeout handler.
138
139 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
140
141**/
142VOID
143TcpConnectTimeout (
144 IN OUT TCP_CB *Tcb
145 )
146{
147 if (!TCP_CONNECTED (Tcb->State)) {
148 DEBUG (
149 (DEBUG_ERROR,
150 "TcpConnectTimeout: connection closed because connection timer timeout for TCB %p\n",
151 Tcb)
152 );
153
154 if (EFI_ABORTED == Tcb->Sk->SockError) {
155 SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);
156 }
157
158 if (TCP_SYN_RCVD == Tcb->State) {
159 DEBUG (
160 (DEBUG_WARN,
161 "TcpConnectTimeout: send reset because connection timer timeout for TCB %p\n",
162 Tcb)
163 );
164
165 TcpResetConnection (Tcb);
166 }
167
168 TcpClose (Tcb);
169 }
170}
171
172/**
173 Timeout handler for TCP retransmission timer.
174
175 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
176
177**/
178VOID
179TcpRexmitTimeout (
180 IN OUT TCP_CB *Tcb
181 )
182{
183 UINT32 FlightSize;
184
185 DEBUG (
186 (DEBUG_WARN,
187 "TcpRexmitTimeout: transmission timeout for TCB %p\n",
188 Tcb)
189 );
190
191 //
192 // Set the congestion window. FlightSize is the
193 // amount of data that has been sent but not
194 // yet ACKed.
195 //
196 FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);
197 Tcb->Ssthresh = MAX ((UINT32)(2 * Tcb->SndMss), FlightSize / 2);
198
199 Tcb->CWnd = Tcb->SndMss;
200 Tcb->LossRecover = Tcb->SndNxt;
201
202 Tcb->LossTimes++;
203 if ((Tcb->LossTimes > Tcb->MaxRexmit) && !TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_CONNECT)) {
204 DEBUG (
205 (DEBUG_ERROR,
206 "TcpRexmitTimeout: connection closed because too many timeouts for TCB %p\n",
207 Tcb)
208 );
209
210 if (EFI_ABORTED == Tcb->Sk->SockError) {
211 SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);
212 }
213
214 TcpClose (Tcb);
215 return;
216 }
217
218 TcpBackoffRto (Tcb);
219 TcpRetransmit (Tcb, Tcb->SndUna);
220 TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);
221
222 Tcb->CongestState = TCP_CONGEST_LOSS;
223
224 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
225}
226
227/**
228 Timeout handler for window probe timer.
229
230 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
231
232**/
233VOID
234TcpProbeTimeout (
235 IN OUT TCP_CB *Tcb
236 )
237{
238 //
239 // This is the timer for sender's SWSA. RFC1122 requires
240 // a timer set for sender's SWSA, and suggest combine it
241 // with window probe timer. If data is sent, don't set
242 // the probe timer, since retransmit timer is on.
243 //
244 if ((TcpDataToSend (Tcb, 1) != 0) && (TcpToSendData (Tcb, 1) > 0)) {
245 ASSERT (TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT) != 0);
246 Tcb->ProbeTimerOn = FALSE;
247 return;
248 }
249
250 TcpSendZeroProbe (Tcb);
251 TcpSetProbeTimer (Tcb);
252}
253
254/**
255 Timeout handler for keepalive timer.
256
257 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
258
259**/
260VOID
261TcpKeepaliveTimeout (
262 IN OUT TCP_CB *Tcb
263 )
264{
265 Tcb->KeepAliveProbes++;
266
267 //
268 // Too many Keep-alive probes, drop the connection
269 //
270 if (Tcb->KeepAliveProbes > Tcb->MaxKeepAlive) {
271 if (EFI_ABORTED == Tcb->Sk->SockError) {
272 SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);
273 }
274
275 TcpClose (Tcb);
276 return;
277 }
278
279 TcpSendZeroProbe (Tcb);
280 TcpSetKeepaliveTimer (Tcb);
281}
282
283/**
284 Timeout handler for FIN_WAIT_2 timer.
285
286 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
287
288**/
289VOID
290TcpFinwait2Timeout (
291 IN OUT TCP_CB *Tcb
292 )
293{
294 DEBUG (
295 (DEBUG_WARN,
296 "TcpFinwait2Timeout: connection closed because FIN_WAIT2 timer timeouts for TCB %p\n",
297 Tcb)
298 );
299
300 TcpClose (Tcb);
301}
302
303/**
304 Timeout handler for 2MSL timer.
305
306 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
307
308**/
309VOID
310Tcp2MSLTimeout (
311 IN OUT TCP_CB *Tcb
312 )
313{
314 DEBUG (
315 (DEBUG_WARN,
316 "Tcp2MSLTimeout: connection closed because TIME_WAIT timer timeouts for TCB %p\n",
317 Tcb)
318 );
319
320 TcpClose (Tcb);
321}
322
323/**
324 Update the timer status and the next expire time according to the timers
325 to expire in a specific future time slot.
326
327 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
328
329**/
330VOID
331TcpUpdateTimer (
332 IN OUT TCP_CB *Tcb
333 )
334{
335 UINT16 Index;
336
337 //
338 // Don't use a too large value to init NextExpire
339 // since mTcpTick wraps around as sequence no does.
340 //
341 Tcb->NextExpire = TCP_EXPIRE_TIME;
342 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);
343
344 for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {
345 if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&
346 TCP_TIME_LT (Tcb->Timer[Index], mTcpTick + Tcb->NextExpire)
347 )
348 {
349 Tcb->NextExpire = TCP_SUB_TIME (Tcb->Timer[Index], mTcpTick);
350 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);
351 }
352 }
353}
354
355/**
356 Enable a TCP timer.
357
358 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
359 @param[in] Timer The index of the timer to be enabled.
360 @param[in] TimeOut The timeout value of this timer.
361
362**/
363VOID
364TcpSetTimer (
365 IN OUT TCP_CB *Tcb,
366 IN UINT16 Timer,
367 IN UINT32 TimeOut
368 )
369{
370 TCP_SET_TIMER (Tcb->EnabledTimer, Timer);
371 Tcb->Timer[Timer] = mTcpTick + TimeOut;
372
373 TcpUpdateTimer (Tcb);
374}
375
376/**
377 Clear one TCP timer.
378
379 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
380 @param[in] Timer The index of the timer to be cleared.
381
382**/
383VOID
384TcpClearTimer (
385 IN OUT TCP_CB *Tcb,
386 IN UINT16 Timer
387 )
388{
389 TCP_CLEAR_TIMER (Tcb->EnabledTimer, Timer);
390 TcpUpdateTimer (Tcb);
391}
392
393/**
394 Clear all TCP timers.
395
396 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
397
398**/
399VOID
400TcpClearAllTimer (
401 IN OUT TCP_CB *Tcb
402 )
403{
404 Tcb->EnabledTimer = 0;
405 TcpUpdateTimer (Tcb);
406}
407
408/**
409 Enable the window prober timer and set the timeout value.
410
411 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
412
413**/
414VOID
415TcpSetProbeTimer (
416 IN OUT TCP_CB *Tcb
417 )
418{
419 if (!Tcb->ProbeTimerOn) {
420 Tcb->ProbeTime = Tcb->Rto;
421 Tcb->ProbeTimerOn = TRUE;
422 } else {
423 Tcb->ProbeTime <<= 1;
424 }
425
426 if (Tcb->ProbeTime < TCP_RTO_MIN) {
427 Tcb->ProbeTime = TCP_RTO_MIN;
428 } else if (Tcb->ProbeTime > TCP_RTO_MAX) {
429 Tcb->ProbeTime = TCP_RTO_MAX;
430 }
431
432 TcpSetTimer (Tcb, TCP_TIMER_PROBE, Tcb->ProbeTime);
433}
434
435/**
436 Enable the keepalive timer and set the timeout value.
437
438 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
439
440**/
441VOID
442TcpSetKeepaliveTimer (
443 IN OUT TCP_CB *Tcb
444 )
445{
446 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE)) {
447 return;
448 }
449
450 //
451 // Set the timer to KeepAliveIdle if either
452 // 1. the keepalive timer is off
453 // 2. The keepalive timer is on, but the idle
454 // is less than KeepAliveIdle, that means the
455 // connection is alive since our last probe.
456 //
457 if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_KEEPALIVE) ||
458 (Tcb->Idle < Tcb->KeepAliveIdle)
459 )
460 {
461 TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAliveIdle);
462 Tcb->KeepAliveProbes = 0;
463 } else {
464 TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAlivePeriod);
465 }
466}
467
468/**
469 Heart beat timer handler.
470
471 @param[in] Context Context of the timer event, ignored.
472
473**/
474VOID
475EFIAPI
476TcpTickingDpc (
477 IN VOID *Context
478 )
479{
480 LIST_ENTRY *Entry;
481 LIST_ENTRY *Next;
482 TCP_CB *Tcb;
483 INT16 Index;
484
485 mTcpTick++;
486
487 //
488 // Don't use LIST_FOR_EACH, which isn't delete safe.
489 //
490 for (Entry = mTcpRunQue.ForwardLink; Entry != &mTcpRunQue; Entry = Next) {
491 Next = Entry->ForwardLink;
492
493 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
494
495 if (Tcb->State == TCP_CLOSED) {
496 continue;
497 }
498
499 //
500 // The connection is doing RTT measurement.
501 //
502 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {
503 Tcb->RttMeasure++;
504 }
505
506 Tcb->Idle++;
507
508 if (Tcb->DelayedAck != 0) {
509 TcpSendAck (Tcb);
510 }
511
512 if ((Tcb->IpInfo->IpVersion == IP_VERSION_6) && (Tcb->Tick > 0)) {
513 Tcb->Tick--;
514 }
515
516 //
517 // No timer is active or no timer expired
518 //
519 if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON) || ((--Tcb->NextExpire) > 0)) {
520 continue;
521 }
522
523 //
524 // Call the timeout handler for each expired timer.
525 //
526 for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {
527 if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) && TCP_TIME_LEQ (Tcb->Timer[Index], mTcpTick)) {
528 //
529 // disable the timer before calling the handler
530 // in case the handler enables it again.
531 //
532 TCP_CLEAR_TIMER (Tcb->EnabledTimer, Index);
533 mTcpTimerHandler[Index](Tcb);
534
535 //
536 // The Tcb may have been deleted by the timer, or
537 // no other timer is set.
538 //
539 if ((Next->BackLink != Entry) || (Tcb->EnabledTimer == 0)) {
540 break;
541 }
542 }
543 }
544
545 //
546 // If the Tcb still exist or some timer is set, update the timer
547 //
548 if (Index == TCP_TIMER_NUMBER) {
549 TcpUpdateTimer (Tcb);
550 }
551 }
552}
553
554/**
555 Heart beat timer handler, queues the DPC at TPL_CALLBACK.
556
557 @param[in] Event Timer event signaled, ignored.
558 @param[in] Context Context of the timer event, ignored.
559
560**/
561VOID
562EFIAPI
563TcpTicking (
564 IN EFI_EVENT Event,
565 IN VOID *Context
566 )
567{
568 QueueDpc (TPL_CALLBACK, TcpTickingDpc, Context);
569}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette