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