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