VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/NetworkPkg/TcpDxe/TcpTimer.c@ 77662

Last change on this file since 77662 was 48674, checked in by vboxsync, 11 years ago

EFI: Export newly imported tinaocore UEFI sources to OSE.

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

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