]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Timer.c
Retire NetLibQueueDpc() and NetLibDispatchDpc() and use QueueDpc() and DispatchDpc...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / Tcp4Timer.c
CommitLineData
8a67d61d 1/** @file\r
dfc1f033 2 TCP timer related functions.\r
3 \r
4Copyright (c) 2005 - 2007, Intel Corporation<BR>\r
8a67d61d 5All rights reserved. This program and the accompanying materials\r
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
120db52c 40 \r
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
8a67d61d 215 return ;\r
216 }\r
217\r
218 TcpSendZeroProbe (Tcb);\r
219 TcpSetProbeTimer (Tcb);\r
220}\r
221\r
222\r
223/**\r
224 Timeout handler for keepalive timer.\r
225\r
226 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
227\r
8a67d61d 228**/\r
8a67d61d 229VOID\r
230TcpKeepaliveTimeout (\r
77f00155 231 IN OUT TCP_CB *Tcb\r
8a67d61d 232 )\r
233{\r
234 Tcb->KeepAliveProbes++;\r
235\r
236 //\r
237 // Too many Keep-alive probes, drop the connection\r
238 //\r
239 if (Tcb->KeepAliveProbes > Tcb->MaxKeepAlive) {\r
240\r
241 if (EFI_ABORTED == Tcb->Sk->SockError) {\r
242 SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);\r
243 }\r
244\r
245 TcpClose (Tcb);\r
246 return ;\r
247 }\r
248\r
249 TcpSendZeroProbe (Tcb);\r
250 TcpSetKeepaliveTimer (Tcb);\r
251}\r
252\r
253\r
254/**\r
255 Timeout handler for FIN_WAIT_2 timer.\r
256\r
257 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
258\r
8a67d61d 259**/\r
8a67d61d 260VOID\r
261TcpFinwait2Timeout (\r
77f00155 262 IN OUT TCP_CB *Tcb\r
8a67d61d 263 )\r
264{\r
e48e37fc 265 DEBUG ((EFI_D_WARN, "TcpFinwait2Timeout: connection closed "\r
0e549d5b 266 "because FIN_WAIT2 timer timeouts for TCB %p\n", Tcb));\r
8a67d61d 267\r
268 TcpClose (Tcb);\r
269}\r
270\r
271\r
272/**\r
273 Timeout handler for 2MSL timer.\r
274\r
275 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
276\r
8a67d61d 277**/\r
8a67d61d 278VOID\r
279Tcp2MSLTimeout (\r
77f00155 280 IN OUT TCP_CB *Tcb\r
8a67d61d 281 )\r
282{\r
e48e37fc 283 DEBUG ((EFI_D_WARN, "Tcp2MSLTimeout: connection closed "\r
0e549d5b 284 "because TIME_WAIT timer timeouts for TCB %p\n", Tcb));\r
8a67d61d 285\r
286 TcpClose (Tcb);\r
287}\r
288\r
289\r
290/**\r
120db52c 291 Update the timer status and the next expire time according to the timers \r
292 to expire in a specific future time slot.\r
8a67d61d 293\r
294 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
295\r
8a67d61d 296**/\r
8a67d61d 297VOID\r
298TcpUpdateTimer (\r
77f00155 299 IN OUT TCP_CB *Tcb\r
8a67d61d 300 )\r
301{\r
302 UINT16 Index;\r
303\r
304 //\r
305 // Don't use a too large value to init NextExpire\r
306 // since mTcpTick wraps around as sequence no does.\r
307 //\r
308 Tcb->NextExpire = 65535;\r
309 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);\r
310\r
311 for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {\r
312\r
313 if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&\r
314 TCP_TIME_LT (Tcb->Timer[Index], mTcpTick + Tcb->NextExpire)) {\r
315\r
316 Tcb->NextExpire = TCP_SUB_TIME (Tcb->Timer[Index], mTcpTick);\r
317 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);\r
318 }\r
319 }\r
320}\r
321\r
322\r
323/**\r
324 Enable a TCP timer.\r
325\r
326 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
327 @param Timer The index of the timer to be enabled.\r
328 @param TimeOut The timeout value of this timer.\r
329\r
8a67d61d 330**/\r
331VOID\r
332TcpSetTimer (\r
77f00155 333 IN OUT TCP_CB *Tcb,\r
334 IN UINT16 Timer,\r
335 IN UINT32 TimeOut\r
8a67d61d 336 )\r
337{\r
338 TCP_SET_TIMER (Tcb->EnabledTimer, Timer);\r
339 Tcb->Timer[Timer] = mTcpTick + TimeOut;\r
340\r
341 TcpUpdateTimer (Tcb);\r
342}\r
343\r
344\r
345/**\r
346 Clear one TCP timer.\r
347\r
348 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
349 @param Timer The index of the timer to be cleared.\r
350\r
8a67d61d 351**/\r
352VOID\r
353TcpClearTimer (\r
77f00155 354 IN OUT TCP_CB *Tcb,\r
355 IN UINT16 Timer\r
8a67d61d 356 )\r
357{\r
358 TCP_CLEAR_TIMER (Tcb->EnabledTimer, Timer);\r
359 TcpUpdateTimer (Tcb);\r
360}\r
361\r
362\r
363/**\r
364 Clear all TCP timers.\r
365\r
366 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
367\r
8a67d61d 368**/\r
369VOID\r
370TcpClearAllTimer (\r
77f00155 371 IN OUT TCP_CB *Tcb\r
8a67d61d 372 )\r
373{\r
374 Tcb->EnabledTimer = 0;\r
375 TcpUpdateTimer (Tcb);\r
376}\r
377\r
378\r
379/**\r
380 Enable the window prober timer and set the timeout value.\r
381\r
382 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
383\r
8a67d61d 384**/\r
385VOID\r
386TcpSetProbeTimer (\r
77f00155 387 IN OUT TCP_CB *Tcb\r
8a67d61d 388 )\r
389{\r
390 if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_PROBE)) {\r
391 Tcb->ProbeTime = Tcb->Rto;\r
392\r
393 } else {\r
394 Tcb->ProbeTime <<= 1;\r
395 }\r
396\r
397 if (Tcb->ProbeTime < TCP_RTO_MIN) {\r
398\r
399 Tcb->ProbeTime = TCP_RTO_MIN;\r
400 } else if (Tcb->ProbeTime > TCP_RTO_MAX) {\r
401\r
402 Tcb->ProbeTime = TCP_RTO_MAX;\r
403 }\r
404\r
405 TcpSetTimer (Tcb, TCP_TIMER_PROBE, Tcb->ProbeTime);\r
406}\r
407\r
408\r
409/**\r
410 Enable the keepalive timer and set the timeout value.\r
411\r
412 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
413\r
8a67d61d 414**/\r
415VOID\r
416TcpSetKeepaliveTimer (\r
77f00155 417 IN OUT TCP_CB *Tcb\r
8a67d61d 418 )\r
419{\r
420 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE)) {\r
421 return ;\r
422\r
423 }\r
424\r
425 //\r
426 // Set the timer to KeepAliveIdle if either\r
427 // 1. the keepalive timer is off\r
428 // 2. The keepalive timer is on, but the idle\r
429 // is less than KeepAliveIdle, that means the\r
430 // connection is alive since our last probe.\r
431 //\r
432 if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_KEEPALIVE) ||\r
433 (Tcb->Idle < Tcb->KeepAliveIdle)) {\r
434\r
435 TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAliveIdle);\r
436 Tcb->KeepAliveProbes = 0;\r
437\r
438 } else {\r
439\r
440 TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAlivePeriod);\r
441 }\r
442}\r
443\r
444\r
445/**\r
446 Backoff the RTO.\r
447\r
448 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
449\r
8a67d61d 450**/\r
451VOID\r
452TcpBackoffRto (\r
77f00155 453 IN OUT TCP_CB *Tcb\r
8a67d61d 454 )\r
455{\r
456 //\r
457 // Fold the RTT estimate if too many times, the estimate\r
458 // may be wrong, fold it. So the next time a valid\r
459 // measurement is sampled, we can start fresh.\r
460 //\r
85511ddf 461 if ((Tcb->LossTimes >= TCP_FOLD_RTT) && (Tcb->SRtt != 0)) {\r
8a67d61d 462 Tcb->RttVar += Tcb->SRtt >> 2;\r
463 Tcb->SRtt = 0;\r
464 }\r
465\r
466 Tcb->Rto <<= 1;\r
467\r
468 if (Tcb->Rto < TCP_RTO_MIN) {\r
469\r
470 Tcb->Rto = TCP_RTO_MIN;\r
471 } else if (Tcb->Rto > TCP_RTO_MAX) {\r
472\r
473 Tcb->Rto = TCP_RTO_MAX;\r
474 }\r
475}\r
476\r
477\r
478/**\r
479 Heart beat timer handler.\r
480\r
120db52c 481 @param Context Context of the timer event, ignored.\r
8a67d61d 482\r
483**/\r
484VOID\r
485EFIAPI\r
36ee91ca 486TcpTickingDpc (\r
8a67d61d 487 IN VOID *Context\r
488 )\r
489{\r
e48e37fc 490 LIST_ENTRY *Entry;\r
491 LIST_ENTRY *Next;\r
8a67d61d 492 TCP_CB *Tcb;\r
493 INT16 Index;\r
494\r
495 mTcpTick++;\r
496 mTcpGlobalIss += 100;\r
497\r
498 //\r
499 // Don't use LIST_FOR_EACH, which isn't delete safe.\r
500 //\r
501 for (Entry = mTcpRunQue.ForwardLink; Entry != &mTcpRunQue; Entry = Next) {\r
502\r
503 Next = Entry->ForwardLink;\r
504\r
505 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
506\r
507 if (Tcb->State == TCP_CLOSED) {\r
508 continue;\r
509 }\r
510 //\r
511 // The connection is doing RTT measurement.\r
512 //\r
513 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
514 Tcb->RttMeasure++;\r
515 }\r
516\r
517 Tcb->Idle++;\r
518\r
85511ddf 519 if (Tcb->DelayedAck != 0) {\r
8a67d61d 520 TcpSendAck (Tcb);\r
521 }\r
522\r
523 //\r
524 // No timer is active or no timer expired\r
525 //\r
526 if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON) ||\r
527 ((--Tcb->NextExpire) > 0)) {\r
528\r
529 continue;\r
530 }\r
531\r
532 //\r
533 // Call the timeout handler for each expired timer.\r
534 //\r
535 for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {\r
536\r
537 if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&\r
538 TCP_TIME_LEQ (Tcb->Timer[Index], mTcpTick)) {\r
539 //\r
540 // disable the timer before calling the handler\r
541 // in case the handler enables it again.\r
542 //\r
543 TCP_CLEAR_TIMER (Tcb->EnabledTimer, Index);\r
544 mTcpTimerHandler[Index](Tcb);\r
545\r
546 //\r
547 // The Tcb may have been deleted by the timer, or\r
548 // no other timer is set.\r
549 //\r
550 if ((Next->BackLink != Entry) ||\r
551 (Tcb->EnabledTimer == 0)) {\r
c191cdd1 552 break;\r
8a67d61d 553 }\r
554 }\r
555 }\r
77f00155 556 \r
557 //\r
558 // If the Tcb still exist or some timer is set, update the timer\r
559 //\r
c191cdd1 560 if (Index == TCP_TIMER_NUMBER) {\r
561 TcpUpdateTimer (Tcb);\r
562 }\r
8a67d61d 563 }\r
564}\r
36ee91ca 565\r
566/**\r
567 Heart beat timer handler, queues the DPC at TPL_CALLBACK.\r
568\r
569 @param Event Timer event signaled, ignored.\r
570 @param Context Context of the timer event, ignored.\r
571\r
36ee91ca 572**/\r
573VOID\r
574EFIAPI\r
575TcpTicking (\r
576 IN EFI_EVENT Event,\r
577 IN VOID *Context\r
578 )\r
579{\r
d8d26fb2 580 QueueDpc (TPL_CALLBACK, TcpTickingDpc, Context);\r
36ee91ca 581}\r
582\r