VirtualBox

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

Last change on this file since 86513 was 85718, checked in by vboxsync, 5 years ago

Devices/EFI: Merge edk-stable202005 and make it build, 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
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
131 Tcb->Rto = TCP_RTO_MIN;
132 } else if (Tcb->Rto > TCP_RTO_MAX) {
133
134 Tcb->Rto = TCP_RTO_MAX;
135 }
136}
137
138/**
139 Connect timeout handler.
140
141 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
142
143**/
144VOID
145TcpConnectTimeout (
146 IN OUT TCP_CB *Tcb
147 )
148{
149 if (!TCP_CONNECTED (Tcb->State)) {
150 DEBUG (
151 (EFI_D_ERROR,
152 "TcpConnectTimeout: connection closed because connection timer timeout for TCB %p\n",
153 Tcb)
154 );
155
156 if (EFI_ABORTED == Tcb->Sk->SockError) {
157 SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);
158 }
159
160 if (TCP_SYN_RCVD == Tcb->State) {
161 DEBUG (
162 (EFI_D_WARN,
163 "TcpConnectTimeout: send reset because connection timer timeout for TCB %p\n",
164 Tcb)
165 );
166
167 TcpResetConnection (Tcb);
168
169 }
170
171 TcpClose (Tcb);
172 }
173}
174
175
176/**
177 Timeout handler for TCP retransmission timer.
178
179 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
180
181**/
182VOID
183TcpRexmitTimeout (
184 IN OUT TCP_CB *Tcb
185 )
186{
187 UINT32 FlightSize;
188
189 DEBUG (
190 (EFI_D_WARN,
191 "TcpRexmitTimeout: transmission timeout for TCB %p\n",
192 Tcb)
193 );
194
195 //
196 // Set the congestion window. FlightSize is the
197 // amount of data that has been sent but not
198 // yet ACKed.
199 //
200 FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);
201 Tcb->Ssthresh = MAX ((UINT32) (2 * Tcb->SndMss), FlightSize / 2);
202
203 Tcb->CWnd = Tcb->SndMss;
204 Tcb->LossRecover = Tcb->SndNxt;
205
206 Tcb->LossTimes++;
207 if ((Tcb->LossTimes > Tcb->MaxRexmit) && !TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_CONNECT)) {
208
209 DEBUG (
210 (EFI_D_ERROR,
211 "TcpRexmitTimeout: connection closed because too many timeouts for TCB %p\n",
212 Tcb)
213 );
214
215 if (EFI_ABORTED == Tcb->Sk->SockError) {
216 SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);
217 }
218
219 TcpClose (Tcb);
220 return ;
221 }
222
223 TcpBackoffRto (Tcb);
224 TcpRetransmit (Tcb, Tcb->SndUna);
225 TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);
226
227 Tcb->CongestState = TCP_CONGEST_LOSS;
228
229 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
230}
231
232/**
233 Timeout handler for window probe timer.
234
235 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
236
237**/
238VOID
239TcpProbeTimeout (
240 IN OUT TCP_CB *Tcb
241 )
242{
243 //
244 // This is the timer for sender's SWSA. RFC1122 requires
245 // a timer set for sender's SWSA, and suggest combine it
246 // with window probe timer. If data is sent, don't set
247 // the probe timer, since retransmit timer is on.
248 //
249 if ((TcpDataToSend (Tcb, 1) != 0) && (TcpToSendData (Tcb, 1) > 0)) {
250
251 ASSERT (TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT) != 0);
252 Tcb->ProbeTimerOn = FALSE;
253 return ;
254 }
255
256 TcpSendZeroProbe (Tcb);
257 TcpSetProbeTimer (Tcb);
258}
259
260/**
261 Timeout handler for keepalive timer.
262
263 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
264
265**/
266VOID
267TcpKeepaliveTimeout (
268 IN OUT TCP_CB *Tcb
269 )
270{
271 Tcb->KeepAliveProbes++;
272
273 //
274 // Too many Keep-alive probes, drop the connection
275 //
276 if (Tcb->KeepAliveProbes > Tcb->MaxKeepAlive) {
277
278 if (EFI_ABORTED == Tcb->Sk->SockError) {
279 SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);
280 }
281
282 TcpClose (Tcb);
283 return ;
284 }
285
286 TcpSendZeroProbe (Tcb);
287 TcpSetKeepaliveTimer (Tcb);
288}
289
290/**
291 Timeout handler for FIN_WAIT_2 timer.
292
293 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
294
295**/
296VOID
297TcpFinwait2Timeout (
298 IN OUT TCP_CB *Tcb
299 )
300{
301 DEBUG (
302 (EFI_D_WARN,
303 "TcpFinwait2Timeout: connection closed because FIN_WAIT2 timer timeouts for TCB %p\n",
304 Tcb)
305 );
306
307 TcpClose (Tcb);
308}
309
310/**
311 Timeout handler for 2MSL timer.
312
313 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
314
315**/
316VOID
317Tcp2MSLTimeout (
318 IN OUT TCP_CB *Tcb
319 )
320{
321 DEBUG (
322 (EFI_D_WARN,
323 "Tcp2MSLTimeout: connection closed because TIME_WAIT timer timeouts for TCB %p\n",
324 Tcb)
325 );
326
327 TcpClose (Tcb);
328}
329
330/**
331 Update the timer status and the next expire time according to the timers
332 to expire in a specific future time slot.
333
334 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
335
336**/
337VOID
338TcpUpdateTimer (
339 IN OUT TCP_CB *Tcb
340 )
341{
342 UINT16 Index;
343
344 //
345 // Don't use a too large value to init NextExpire
346 // since mTcpTick wraps around as sequence no does.
347 //
348 Tcb->NextExpire = TCP_EXPIRE_TIME;
349 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);
350
351 for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {
352
353 if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&
354 TCP_TIME_LT (Tcb->Timer[Index], mTcpTick + Tcb->NextExpire)
355 ) {
356
357 Tcb->NextExpire = TCP_SUB_TIME (Tcb->Timer[Index], mTcpTick);
358 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);
359 }
360 }
361}
362
363/**
364 Enable a TCP timer.
365
366 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
367 @param[in] Timer The index of the timer to be enabled.
368 @param[in] TimeOut The timeout value of this timer.
369
370**/
371VOID
372TcpSetTimer (
373 IN OUT TCP_CB *Tcb,
374 IN UINT16 Timer,
375 IN UINT32 TimeOut
376 )
377{
378 TCP_SET_TIMER (Tcb->EnabledTimer, Timer);
379 Tcb->Timer[Timer] = mTcpTick + TimeOut;
380
381 TcpUpdateTimer (Tcb);
382}
383
384/**
385 Clear one TCP timer.
386
387 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
388 @param[in] Timer The index of the timer to be cleared.
389
390**/
391VOID
392TcpClearTimer (
393 IN OUT TCP_CB *Tcb,
394 IN UINT16 Timer
395 )
396{
397 TCP_CLEAR_TIMER (Tcb->EnabledTimer, Timer);
398 TcpUpdateTimer (Tcb);
399}
400
401/**
402 Clear all TCP timers.
403
404 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
405
406**/
407VOID
408TcpClearAllTimer (
409 IN OUT TCP_CB *Tcb
410 )
411{
412 Tcb->EnabledTimer = 0;
413 TcpUpdateTimer (Tcb);
414}
415
416/**
417 Enable the window prober timer and set the timeout value.
418
419 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
420
421**/
422VOID
423TcpSetProbeTimer (
424 IN OUT TCP_CB *Tcb
425 )
426{
427 if (!Tcb->ProbeTimerOn) {
428 Tcb->ProbeTime = Tcb->Rto;
429 Tcb->ProbeTimerOn = TRUE;
430
431 } else {
432 Tcb->ProbeTime <<= 1;
433 }
434
435 if (Tcb->ProbeTime < TCP_RTO_MIN) {
436
437 Tcb->ProbeTime = TCP_RTO_MIN;
438 } else if (Tcb->ProbeTime > TCP_RTO_MAX) {
439
440 Tcb->ProbeTime = TCP_RTO_MAX;
441 }
442
443 TcpSetTimer (Tcb, TCP_TIMER_PROBE, Tcb->ProbeTime);
444}
445
446/**
447 Enable the keepalive timer and set the timeout value.
448
449 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
450
451**/
452VOID
453TcpSetKeepaliveTimer (
454 IN OUT TCP_CB *Tcb
455 )
456{
457 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE)) {
458 return ;
459
460 }
461
462 //
463 // Set the timer to KeepAliveIdle if either
464 // 1. the keepalive timer is off
465 // 2. The keepalive timer is on, but the idle
466 // is less than KeepAliveIdle, that means the
467 // connection is alive since our last probe.
468 //
469 if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_KEEPALIVE) ||
470 (Tcb->Idle < Tcb->KeepAliveIdle)
471 ) {
472
473 TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAliveIdle);
474 Tcb->KeepAliveProbes = 0;
475
476 } else {
477
478 TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAlivePeriod);
479 }
480}
481
482/**
483 Heart beat timer handler.
484
485 @param[in] Context Context of the timer event, ignored.
486
487**/
488VOID
489EFIAPI
490TcpTickingDpc (
491 IN VOID *Context
492 )
493{
494 LIST_ENTRY *Entry;
495 LIST_ENTRY *Next;
496 TCP_CB *Tcb;
497 INT16 Index;
498
499 mTcpTick++;
500 mTcpGlobalIss += TCP_ISS_INCREMENT_2;
501
502 //
503 // Don't use LIST_FOR_EACH, which isn't delete safe.
504 //
505 for (Entry = mTcpRunQue.ForwardLink; Entry != &mTcpRunQue; Entry = Next) {
506
507 Next = Entry->ForwardLink;
508
509 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
510
511 if (Tcb->State == TCP_CLOSED) {
512 continue;
513 }
514 //
515 // The connection is doing RTT measurement.
516 //
517 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {
518 Tcb->RttMeasure++;
519 }
520
521 Tcb->Idle++;
522
523 if (Tcb->DelayedAck != 0) {
524 TcpSendAck (Tcb);
525 }
526
527 if (Tcb->IpInfo->IpVersion == IP_VERSION_6 && Tcb->Tick > 0) {
528 Tcb->Tick--;
529 }
530
531 //
532 // No timer is active or no timer expired
533 //
534 if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON) || ((--Tcb->NextExpire) > 0)) {
535
536 continue;
537 }
538
539 //
540 // Call the timeout handler for each expired timer.
541 //
542 for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {
543
544 if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) && TCP_TIME_LEQ (Tcb->Timer[Index], mTcpTick)) {
545 //
546 // disable the timer before calling the handler
547 // in case the handler enables it again.
548 //
549 TCP_CLEAR_TIMER (Tcb->EnabledTimer, Index);
550 mTcpTimerHandler[Index](Tcb);
551
552 //
553 // The Tcb may have been deleted by the timer, or
554 // no other timer is set.
555 //
556 if ((Next->BackLink != Entry) || (Tcb->EnabledTimer == 0)) {
557 break;
558 }
559 }
560 }
561
562 //
563 // If the Tcb still exist or some timer is set, update the timer
564 //
565 if (Index == TCP_TIMER_NUMBER) {
566 TcpUpdateTimer (Tcb);
567 }
568 }
569}
570
571/**
572 Heart beat timer handler, queues the DPC at TPL_CALLBACK.
573
574 @param[in] Event Timer event signaled, ignored.
575 @param[in] Context Context of the timer event, ignored.
576
577**/
578VOID
579EFIAPI
580TcpTicking (
581 IN EFI_EVENT Event,
582 IN VOID *Context
583 )
584{
585 QueueDpc (TPL_CALLBACK, TcpTickingDpc, Context);
586}
587
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