]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Timer.c
Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / Tcp4Timer.c
CommitLineData
8a67d61d 1/** @file\r
2\r
3Copyright (c) 2005 - 2006, Intel Corporation\r
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
108 TCP4_DEBUG_ERROR (("TcpConnectTimeout: connection closed "\r
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
116 TCP4_DEBUG_WARN (("TcpConnectTimeout: send reset because "\r
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
144 TCP4_DEBUG_WARN (("TcpRexmitTimeout: transmission "\r
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
153 Tcb->Ssthresh = NET_MAX ((UINT32) (2 * Tcb->SndMss), FlightSize / 2);\r
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
162 TCP4_DEBUG_ERROR (("TcpRexmitTimeout: connection closed "\r
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
262 TCP4_DEBUG_WARN (("TcpFinwait2Timeout: connection closed "\r
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
283 TCP4_DEBUG_WARN (("Tcp2MSLTimeout: connection closed "\r
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
497 @param Event Timer event signaled, ignored.\r
498 @param Context Context of the timer event, ignored.\r
499\r
500 @return None.\r
501\r
502**/\r
503VOID\r
504EFIAPI\r
505TcpTicking (\r
506 IN EFI_EVENT Event,\r
507 IN VOID *Context\r
508 )\r
509{\r
510 NET_LIST_ENTRY *Entry;\r
511 NET_LIST_ENTRY *Next;\r
512 TCP_CB *Tcb;\r
513 INT16 Index;\r
514\r
515 mTcpTick++;\r
516 mTcpGlobalIss += 100;\r
517\r
518 //\r
519 // Don't use LIST_FOR_EACH, which isn't delete safe.\r
520 //\r
521 for (Entry = mTcpRunQue.ForwardLink; Entry != &mTcpRunQue; Entry = Next) {\r
522\r
523 Next = Entry->ForwardLink;\r
524\r
525 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
526\r
527 if (Tcb->State == TCP_CLOSED) {\r
528 continue;\r
529 }\r
530 //\r
531 // The connection is doing RTT measurement.\r
532 //\r
533 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
534 Tcb->RttMeasure++;\r
535 }\r
536\r
537 Tcb->Idle++;\r
538\r
539 if (Tcb->DelayedAck) {\r
540 TcpSendAck (Tcb);\r
541 }\r
542\r
543 //\r
544 // No timer is active or no timer expired\r
545 //\r
546 if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON) ||\r
547 ((--Tcb->NextExpire) > 0)) {\r
548\r
549 continue;\r
550 }\r
551\r
552 //\r
553 // Call the timeout handler for each expired timer.\r
554 //\r
555 for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {\r
556\r
557 if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&\r
558 TCP_TIME_LEQ (Tcb->Timer[Index], mTcpTick)) {\r
559 //\r
560 // disable the timer before calling the handler\r
561 // in case the handler enables it again.\r
562 //\r
563 TCP_CLEAR_TIMER (Tcb->EnabledTimer, Index);\r
564 mTcpTimerHandler[Index](Tcb);\r
565\r
566 //\r
567 // The Tcb may have been deleted by the timer, or\r
568 // no other timer is set.\r
569 //\r
570 if ((Next->BackLink != Entry) ||\r
571 (Tcb->EnabledTimer == 0)) {\r
572\r
573 goto NextConnection;\r
574 }\r
575 }\r
576 }\r
577\r
578 TcpUpdateTimer (Tcb);\r
579NextConnection:\r
580 ;\r
581 }\r
582}\r