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