]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/TcpDxe/TcpTimer.c
Fix a bug about the iSCSI DHCP dependency issue.
[mirror_edk2.git] / NetworkPkg / TcpDxe / TcpTimer.c
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
18 UINT32 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 **/
26 VOID
27 TcpConnectTimeout (
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 **/
37 VOID
38 TcpRexmitTimeout (
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 **/
48 VOID
49 TcpProbeTimeout (
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 **/
59 VOID
60 TcpKeepaliveTimeout (
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 **/
70 VOID
71 TcpFinwait2Timeout (
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 **/
81 VOID
82 Tcp2MSLTimeout (
83 IN OUT TCP_CB *Tcb
84 );
85
86 TCP_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 **/
101 VOID
102 TcpClose (
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 **/
118 VOID
119 TcpBackoffRto (
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 **/
150 VOID
151 TcpConnectTimeout (
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 **/
188 VOID
189 TcpRexmitTimeout (
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 **/
244 VOID
245 TcpProbeTimeout (
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 **/
272 VOID
273 TcpKeepaliveTimeout (
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 **/
302 VOID
303 TcpFinwait2Timeout (
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 **/
322 VOID
323 Tcp2MSLTimeout (
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 **/
343 VOID
344 TcpUpdateTimer (
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 **/
377 VOID
378 TcpSetTimer (
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 **/
397 VOID
398 TcpClearTimer (
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 **/
413 VOID
414 TcpClearAllTimer (
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 **/
428 VOID
429 TcpSetProbeTimer (
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 **/
458 VOID
459 TcpSetKeepaliveTimer (
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 **/
494 VOID
495 EFIAPI
496 TcpTickingDpc (
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 **/
584 VOID
585 EFIAPI
586 TcpTicking (
587 IN EFI_EVENT Event,
588 IN VOID *Context
589 )
590 {
591 QueueDpc (TPL_CALLBACK, TcpTickingDpc, Context);
592 }
593