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