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