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