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