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