1/** @file 2 TCP timer related functions. 3 4Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR> 5This program and the accompanying materials 6are licensed and made available under the terms and conditions of the BSD License 7which accompanies this distribution. The full text of the license may be found at 8http://opensource.org/licenses/bsd-license.php<BR> 9 10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13**/ 14 15#include "Tcp4Main.h" 16 17UINT32 mTcpTick = 1000; 18 19/** 20 Connect timeout handler. 21 22 @param Tcb Pointer to the TCP_CB of this TCP instance. 23 24**/ 25VOID 26TcpConnectTimeout ( 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**/ 36VOID 37TcpRexmitTimeout ( 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**/ 47VOID 48TcpProbeTimeout ( 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**/ 58VOID 59TcpKeepaliveTimeout ( 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**/ 69VOID 70TcpFinwait2Timeout ( 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**/ 80VOID 81Tcp2MSLTimeout ( 82 IN OUT TCP_CB *Tcb 83 ); 84 85TCP_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**/ 100VOID 101TcpClose ( 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**/ 118VOID 119TcpConnectTimeout ( 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**/ 150VOID 151TcpRexmitTimeout ( 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**/ 201VOID 202TcpProbeTimeout ( 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 Tcb->ProbeTimerOn = FALSE; 216 return ; 217 } 218 219 TcpSendZeroProbe (Tcb); 220 TcpSetProbeTimer (Tcb); 221} 222 223 224/** 225 Timeout handler for keepalive timer. 226 227 @param Tcb Pointer to the TCP_CB of this TCP instance. 228 229**/ 230VOID 231TcpKeepaliveTimeout ( 232 IN OUT TCP_CB *Tcb 233 ) 234{ 235 Tcb->KeepAliveProbes++; 236 237 // 238 // Too many Keep-alive probes, drop the connection 239 // 240 if (Tcb->KeepAliveProbes > Tcb->MaxKeepAlive) { 241 242 if (EFI_ABORTED == Tcb->Sk->SockError) { 243 SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT); 244 } 245 246 TcpClose (Tcb); 247 return ; 248 } 249 250 TcpSendZeroProbe (Tcb); 251 TcpSetKeepaliveTimer (Tcb); 252} 253 254 255/** 256 Timeout handler for FIN_WAIT_2 timer. 257 258 @param Tcb Pointer to the TCP_CB of this TCP instance. 259 260**/ 261VOID 262TcpFinwait2Timeout ( 263 IN OUT TCP_CB *Tcb 264 ) 265{ 266 DEBUG ((EFI_D_WARN, "TcpFinwait2Timeout: connection closed " 267 "because FIN_WAIT2 timer timeouts for TCB %p\n", Tcb)); 268 269 TcpClose (Tcb); 270} 271 272 273/** 274 Timeout handler for 2MSL timer. 275 276 @param Tcb Pointer to the TCP_CB of this TCP instance. 277 278**/ 279VOID 280Tcp2MSLTimeout ( 281 IN OUT TCP_CB *Tcb 282 ) 283{ 284 DEBUG ((EFI_D_WARN, "Tcp2MSLTimeout: connection closed " 285 "because TIME_WAIT timer timeouts for TCB %p\n", Tcb)); 286 287 TcpClose (Tcb); 288} 289 290 291/** 292 Update the timer status and the next expire time according to the timers 293 to expire in a specific future time slot. 294 295 @param Tcb Pointer to the TCP_CB of this TCP instance. 296 297**/ 298VOID 299TcpUpdateTimer ( 300 IN OUT TCP_CB *Tcb 301 ) 302{ 303 UINT16 Index; 304 305 // 306 // Don't use a too large value to init NextExpire 307 // since mTcpTick wraps around as sequence no does. 308 // 309 Tcb->NextExpire = 65535; 310 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON); 311 312 for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) { 313 314 if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) && 315 TCP_TIME_LT (Tcb->Timer[Index], mTcpTick + Tcb->NextExpire)) { 316 317 Tcb->NextExpire = TCP_SUB_TIME (Tcb->Timer[Index], mTcpTick); 318 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON); 319 } 320 } 321} 322 323 324/** 325 Enable a TCP timer. 326 327 @param Tcb Pointer to the TCP_CB of this TCP instance. 328 @param Timer The index of the timer to be enabled. 329 @param TimeOut The timeout value of this timer. 330 331**/ 332VOID 333TcpSetTimer ( 334 IN OUT TCP_CB *Tcb, 335 IN UINT16 Timer, 336 IN UINT32 TimeOut 337 ) 338{ 339 TCP_SET_TIMER (Tcb->EnabledTimer, Timer); 340 Tcb->Timer[Timer] = mTcpTick + TimeOut; 341 342 TcpUpdateTimer (Tcb); 343} 344 345 346/** 347 Clear one TCP timer. 348 349 @param Tcb Pointer to the TCP_CB of this TCP instance. 350 @param Timer The index of the timer to be cleared. 351 352**/ 353VOID 354TcpClearTimer ( 355 IN OUT TCP_CB *Tcb, 356 IN UINT16 Timer 357 ) 358{ 359 TCP_CLEAR_TIMER (Tcb->EnabledTimer, Timer); 360 TcpUpdateTimer (Tcb); 361} 362 363 364/** 365 Clear all TCP timers. 366 367 @param Tcb Pointer to the TCP_CB of this TCP instance. 368 369**/ 370VOID 371TcpClearAllTimer ( 372 IN OUT TCP_CB *Tcb 373 ) 374{ 375 Tcb->EnabledTimer = 0; 376 TcpUpdateTimer (Tcb); 377} 378 379 380/** 381 Enable the window prober timer and set the timeout value. 382 383 @param Tcb Pointer to the TCP_CB of this TCP instance. 384 385**/ 386VOID 387TcpSetProbeTimer ( 388 IN OUT TCP_CB *Tcb 389 ) 390{ 391 if (!Tcb->ProbeTimerOn) { 392 Tcb->ProbeTime = Tcb->Rto; 393 Tcb->ProbeTimerOn = TRUE; 394 395 } else { 396 Tcb->ProbeTime <<= 1; 397 } 398 399 if (Tcb->ProbeTime < TCP_RTO_MIN) { 400 401 Tcb->ProbeTime = TCP_RTO_MIN; 402 } else if (Tcb->ProbeTime > TCP_RTO_MAX) { 403 404 Tcb->ProbeTime = TCP_RTO_MAX; 405 } 406 407 TcpSetTimer (Tcb, TCP_TIMER_PROBE, Tcb->ProbeTime); 408} 409 410 411/** 412 Enable the keepalive timer and set the timeout value. 413 414 @param Tcb Pointer to the TCP_CB of this TCP instance. 415 416**/ 417VOID 418TcpSetKeepaliveTimer ( 419 IN OUT TCP_CB *Tcb 420 ) 421{ 422 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE)) { 423 return ; 424 425 } 426 427 // 428 // Set the timer to KeepAliveIdle if either 429 // 1. the keepalive timer is off 430 // 2. The keepalive timer is on, but the idle 431 // is less than KeepAliveIdle, that means the 432 // connection is alive since our last probe. 433 // 434 if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_KEEPALIVE) || 435 (Tcb->Idle < Tcb->KeepAliveIdle)) { 436 437 TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAliveIdle); 438 Tcb->KeepAliveProbes = 0; 439 440 } else { 441 442 TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAlivePeriod); 443 } 444} 445 446 447/** 448 Backoff the RTO. 449 450 @param Tcb Pointer to the TCP_CB of this TCP instance. 451 452**/ 453VOID 454TcpBackoffRto ( 455 IN OUT TCP_CB *Tcb 456 ) 457{ 458 // 459 // Fold the RTT estimate if too many times, the estimate 460 // may be wrong, fold it. So the next time a valid 461 // measurement is sampled, we can start fresh. 462 // 463 if ((Tcb->LossTimes >= TCP_FOLD_RTT) && (Tcb->SRtt != 0)) { 464 Tcb->RttVar += Tcb->SRtt >> 2; 465 Tcb->SRtt = 0; 466 } 467 468 Tcb->Rto <<= 1; 469 470 if (Tcb->Rto < TCP_RTO_MIN) { 471 472 Tcb->Rto = TCP_RTO_MIN; 473 } else if (Tcb->Rto > TCP_RTO_MAX) { 474 475 Tcb->Rto = TCP_RTO_MAX; 476 } 477} 478 479 480/** 481 Heart beat timer handler. 482 483 @param Context Context of the timer event, ignored. 484 485**/ 486VOID 487EFIAPI 488TcpTickingDpc ( 489 IN VOID *Context 490 ) 491{ 492 LIST_ENTRY *Entry; 493 LIST_ENTRY *Next; 494 TCP_CB *Tcb; 495 INT16 Index; 496 497 mTcpTick++; 498 mTcpGlobalIss += 100; 499 500 // 501 // Don't use LIST_FOR_EACH, which isn't delete safe. 502 // 503 for (Entry = mTcpRunQue.ForwardLink; Entry != &mTcpRunQue; Entry = Next) { 504 505 Next = Entry->ForwardLink; 506 507 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List); 508 509 if (Tcb->State == TCP_CLOSED) { 510 continue; 511 } 512 // 513 // The connection is doing RTT measurement. 514 // 515 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) { 516 Tcb->RttMeasure++; 517 } 518 519 Tcb->Idle++; 520 521 if (Tcb->DelayedAck != 0) { 522 TcpSendAck (Tcb); 523 } 524 525 // 526 // No timer is active or no timer expired 527 // 528 if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON) || 529 ((--Tcb->NextExpire) > 0)) { 530 531 continue; 532 } 533 534 // 535 // Call the timeout handler for each expired timer. 536 // 537 for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) { 538 539 if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) && 540 TCP_TIME_LEQ (Tcb->Timer[Index], mTcpTick)) { 541 // 542 // disable the timer before calling the handler 543 // in case the handler enables it again. 544 // 545 TCP_CLEAR_TIMER (Tcb->EnabledTimer, Index); 546 mTcpTimerHandler[Index](Tcb); 547 548 // 549 // The Tcb may have been deleted by the timer, or 550 // no other timer is set. 551 // 552 if ((Next->BackLink != Entry) || 553 (Tcb->EnabledTimer == 0)) { 554 break; 555 } 556 } 557 } 558 559 // 560 // If the Tcb still exist or some timer is set, update the timer 561 // 562 if (Index == TCP_TIMER_NUMBER) { 563 TcpUpdateTimer (Tcb); 564 } 565 } 566} 567 568/** 569 Heart beat timer handler, queues the DPC at TPL_CALLBACK. 570 571 @param Event Timer event signaled, ignored. 572 @param Context Context of the timer event, ignored. 573 574**/ 575VOID 576EFIAPI 577TcpTicking ( 578 IN EFI_EVENT Event, 579 IN VOID *Context 580 ) 581{ 582 QueueDpc (TPL_CALLBACK, TcpTickingDpc, Context); 583} 584 585