TcpTimer.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. /** @file
  2. TCP timer related functions.
  3. Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "TcpMain.h"
  7. UINT32 mTcpTick = 1000;
  8. /**
  9. Connect timeout handler.
  10. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  11. **/
  12. VOID
  13. TcpConnectTimeout (
  14. IN OUT TCP_CB *Tcb
  15. );
  16. /**
  17. Timeout handler for TCP retransmission timer.
  18. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  19. **/
  20. VOID
  21. TcpRexmitTimeout (
  22. IN OUT TCP_CB *Tcb
  23. );
  24. /**
  25. Timeout handler for window probe timer.
  26. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  27. **/
  28. VOID
  29. TcpProbeTimeout (
  30. IN OUT TCP_CB *Tcb
  31. );
  32. /**
  33. Timeout handler for keepalive timer.
  34. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  35. **/
  36. VOID
  37. TcpKeepaliveTimeout (
  38. IN OUT TCP_CB *Tcb
  39. );
  40. /**
  41. Timeout handler for FIN_WAIT_2 timer.
  42. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  43. **/
  44. VOID
  45. TcpFinwait2Timeout (
  46. IN OUT TCP_CB *Tcb
  47. );
  48. /**
  49. Timeout handler for 2MSL timer.
  50. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  51. **/
  52. VOID
  53. Tcp2MSLTimeout (
  54. IN OUT TCP_CB *Tcb
  55. );
  56. TCP_TIMER_HANDLER mTcpTimerHandler[TCP_TIMER_NUMBER] = {
  57. TcpConnectTimeout,
  58. TcpRexmitTimeout,
  59. TcpProbeTimeout,
  60. TcpKeepaliveTimeout,
  61. TcpFinwait2Timeout,
  62. Tcp2MSLTimeout,
  63. };
  64. /**
  65. Close the TCP connection.
  66. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  67. **/
  68. VOID
  69. TcpClose (
  70. IN OUT TCP_CB *Tcb
  71. )
  72. {
  73. NetbufFreeList (&Tcb->SndQue);
  74. NetbufFreeList (&Tcb->RcvQue);
  75. TcpSetState (Tcb, TCP_CLOSED);
  76. }
  77. /**
  78. Backoff the RTO.
  79. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  80. **/
  81. VOID
  82. TcpBackoffRto (
  83. IN OUT TCP_CB *Tcb
  84. )
  85. {
  86. //
  87. // Fold the RTT estimate if too many times, the estimate
  88. // may be wrong, fold it. So the next time a valid
  89. // measurement is sampled, we can start fresh.
  90. //
  91. if ((Tcb->LossTimes >= TCP_FOLD_RTT) && (Tcb->SRtt != 0)) {
  92. Tcb->RttVar += Tcb->SRtt >> 2;
  93. Tcb->SRtt = 0;
  94. }
  95. Tcb->Rto <<= 1;
  96. if (Tcb->Rto < TCP_RTO_MIN) {
  97. Tcb->Rto = TCP_RTO_MIN;
  98. } else if (Tcb->Rto > TCP_RTO_MAX) {
  99. Tcb->Rto = TCP_RTO_MAX;
  100. }
  101. }
  102. /**
  103. Connect timeout handler.
  104. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  105. **/
  106. VOID
  107. TcpConnectTimeout (
  108. IN OUT TCP_CB *Tcb
  109. )
  110. {
  111. if (!TCP_CONNECTED (Tcb->State)) {
  112. DEBUG (
  113. (DEBUG_ERROR,
  114. "TcpConnectTimeout: connection closed because connection timer timeout for TCB %p\n",
  115. Tcb)
  116. );
  117. if (EFI_ABORTED == Tcb->Sk->SockError) {
  118. SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);
  119. }
  120. if (TCP_SYN_RCVD == Tcb->State) {
  121. DEBUG (
  122. (DEBUG_WARN,
  123. "TcpConnectTimeout: send reset because connection timer timeout for TCB %p\n",
  124. Tcb)
  125. );
  126. TcpResetConnection (Tcb);
  127. }
  128. TcpClose (Tcb);
  129. }
  130. }
  131. /**
  132. Timeout handler for TCP retransmission timer.
  133. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  134. **/
  135. VOID
  136. TcpRexmitTimeout (
  137. IN OUT TCP_CB *Tcb
  138. )
  139. {
  140. UINT32 FlightSize;
  141. DEBUG (
  142. (DEBUG_WARN,
  143. "TcpRexmitTimeout: transmission timeout for TCB %p\n",
  144. Tcb)
  145. );
  146. //
  147. // Set the congestion window. FlightSize is the
  148. // amount of data that has been sent but not
  149. // yet ACKed.
  150. //
  151. FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);
  152. Tcb->Ssthresh = MAX ((UINT32)(2 * Tcb->SndMss), FlightSize / 2);
  153. Tcb->CWnd = Tcb->SndMss;
  154. Tcb->LossRecover = Tcb->SndNxt;
  155. Tcb->LossTimes++;
  156. if ((Tcb->LossTimes > Tcb->MaxRexmit) && !TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_CONNECT)) {
  157. DEBUG (
  158. (DEBUG_ERROR,
  159. "TcpRexmitTimeout: connection closed because too many timeouts for TCB %p\n",
  160. Tcb)
  161. );
  162. if (EFI_ABORTED == Tcb->Sk->SockError) {
  163. SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);
  164. }
  165. TcpClose (Tcb);
  166. return;
  167. }
  168. TcpBackoffRto (Tcb);
  169. TcpRetransmit (Tcb, Tcb->SndUna);
  170. TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);
  171. Tcb->CongestState = TCP_CONGEST_LOSS;
  172. TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
  173. }
  174. /**
  175. Timeout handler for window probe timer.
  176. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  177. **/
  178. VOID
  179. TcpProbeTimeout (
  180. IN OUT TCP_CB *Tcb
  181. )
  182. {
  183. //
  184. // This is the timer for sender's SWSA. RFC1122 requires
  185. // a timer set for sender's SWSA, and suggest combine it
  186. // with window probe timer. If data is sent, don't set
  187. // the probe timer, since retransmit timer is on.
  188. //
  189. if ((TcpDataToSend (Tcb, 1) != 0) && (TcpToSendData (Tcb, 1) > 0)) {
  190. ASSERT (TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT) != 0);
  191. Tcb->ProbeTimerOn = FALSE;
  192. return;
  193. }
  194. TcpSendZeroProbe (Tcb);
  195. TcpSetProbeTimer (Tcb);
  196. }
  197. /**
  198. Timeout handler for keepalive timer.
  199. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  200. **/
  201. VOID
  202. TcpKeepaliveTimeout (
  203. IN OUT TCP_CB *Tcb
  204. )
  205. {
  206. Tcb->KeepAliveProbes++;
  207. //
  208. // Too many Keep-alive probes, drop the connection
  209. //
  210. if (Tcb->KeepAliveProbes > Tcb->MaxKeepAlive) {
  211. if (EFI_ABORTED == Tcb->Sk->SockError) {
  212. SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);
  213. }
  214. TcpClose (Tcb);
  215. return;
  216. }
  217. TcpSendZeroProbe (Tcb);
  218. TcpSetKeepaliveTimer (Tcb);
  219. }
  220. /**
  221. Timeout handler for FIN_WAIT_2 timer.
  222. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  223. **/
  224. VOID
  225. TcpFinwait2Timeout (
  226. IN OUT TCP_CB *Tcb
  227. )
  228. {
  229. DEBUG (
  230. (DEBUG_WARN,
  231. "TcpFinwait2Timeout: connection closed because FIN_WAIT2 timer timeouts for TCB %p\n",
  232. Tcb)
  233. );
  234. TcpClose (Tcb);
  235. }
  236. /**
  237. Timeout handler for 2MSL timer.
  238. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  239. **/
  240. VOID
  241. Tcp2MSLTimeout (
  242. IN OUT TCP_CB *Tcb
  243. )
  244. {
  245. DEBUG (
  246. (DEBUG_WARN,
  247. "Tcp2MSLTimeout: connection closed because TIME_WAIT timer timeouts for TCB %p\n",
  248. Tcb)
  249. );
  250. TcpClose (Tcb);
  251. }
  252. /**
  253. Update the timer status and the next expire time according to the timers
  254. to expire in a specific future time slot.
  255. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  256. **/
  257. VOID
  258. TcpUpdateTimer (
  259. IN OUT TCP_CB *Tcb
  260. )
  261. {
  262. UINT16 Index;
  263. //
  264. // Don't use a too large value to init NextExpire
  265. // since mTcpTick wraps around as sequence no does.
  266. //
  267. Tcb->NextExpire = TCP_EXPIRE_TIME;
  268. TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);
  269. for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {
  270. if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&
  271. TCP_TIME_LT (Tcb->Timer[Index], mTcpTick + Tcb->NextExpire)
  272. )
  273. {
  274. Tcb->NextExpire = TCP_SUB_TIME (Tcb->Timer[Index], mTcpTick);
  275. TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);
  276. }
  277. }
  278. }
  279. /**
  280. Enable a TCP timer.
  281. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  282. @param[in] Timer The index of the timer to be enabled.
  283. @param[in] TimeOut The timeout value of this timer.
  284. **/
  285. VOID
  286. TcpSetTimer (
  287. IN OUT TCP_CB *Tcb,
  288. IN UINT16 Timer,
  289. IN UINT32 TimeOut
  290. )
  291. {
  292. TCP_SET_TIMER (Tcb->EnabledTimer, Timer);
  293. Tcb->Timer[Timer] = mTcpTick + TimeOut;
  294. TcpUpdateTimer (Tcb);
  295. }
  296. /**
  297. Clear one TCP timer.
  298. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  299. @param[in] Timer The index of the timer to be cleared.
  300. **/
  301. VOID
  302. TcpClearTimer (
  303. IN OUT TCP_CB *Tcb,
  304. IN UINT16 Timer
  305. )
  306. {
  307. TCP_CLEAR_TIMER (Tcb->EnabledTimer, Timer);
  308. TcpUpdateTimer (Tcb);
  309. }
  310. /**
  311. Clear all TCP timers.
  312. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  313. **/
  314. VOID
  315. TcpClearAllTimer (
  316. IN OUT TCP_CB *Tcb
  317. )
  318. {
  319. Tcb->EnabledTimer = 0;
  320. TcpUpdateTimer (Tcb);
  321. }
  322. /**
  323. Enable the window prober timer and set the timeout value.
  324. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  325. **/
  326. VOID
  327. TcpSetProbeTimer (
  328. IN OUT TCP_CB *Tcb
  329. )
  330. {
  331. if (!Tcb->ProbeTimerOn) {
  332. Tcb->ProbeTime = Tcb->Rto;
  333. Tcb->ProbeTimerOn = TRUE;
  334. } else {
  335. Tcb->ProbeTime <<= 1;
  336. }
  337. if (Tcb->ProbeTime < TCP_RTO_MIN) {
  338. Tcb->ProbeTime = TCP_RTO_MIN;
  339. } else if (Tcb->ProbeTime > TCP_RTO_MAX) {
  340. Tcb->ProbeTime = TCP_RTO_MAX;
  341. }
  342. TcpSetTimer (Tcb, TCP_TIMER_PROBE, Tcb->ProbeTime);
  343. }
  344. /**
  345. Enable the keepalive timer and set the timeout value.
  346. @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
  347. **/
  348. VOID
  349. TcpSetKeepaliveTimer (
  350. IN OUT TCP_CB *Tcb
  351. )
  352. {
  353. if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE)) {
  354. return;
  355. }
  356. //
  357. // Set the timer to KeepAliveIdle if either
  358. // 1. the keepalive timer is off
  359. // 2. The keepalive timer is on, but the idle
  360. // is less than KeepAliveIdle, that means the
  361. // connection is alive since our last probe.
  362. //
  363. if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_KEEPALIVE) ||
  364. (Tcb->Idle < Tcb->KeepAliveIdle)
  365. )
  366. {
  367. TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAliveIdle);
  368. Tcb->KeepAliveProbes = 0;
  369. } else {
  370. TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAlivePeriod);
  371. }
  372. }
  373. /**
  374. Heart beat timer handler.
  375. @param[in] Context Context of the timer event, ignored.
  376. **/
  377. VOID
  378. EFIAPI
  379. TcpTickingDpc (
  380. IN VOID *Context
  381. )
  382. {
  383. LIST_ENTRY *Entry;
  384. LIST_ENTRY *Next;
  385. TCP_CB *Tcb;
  386. INT16 Index;
  387. mTcpTick++;
  388. mTcpGlobalIss += TCP_ISS_INCREMENT_2;
  389. //
  390. // Don't use LIST_FOR_EACH, which isn't delete safe.
  391. //
  392. for (Entry = mTcpRunQue.ForwardLink; Entry != &mTcpRunQue; Entry = Next) {
  393. Next = Entry->ForwardLink;
  394. Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
  395. if (Tcb->State == TCP_CLOSED) {
  396. continue;
  397. }
  398. //
  399. // The connection is doing RTT measurement.
  400. //
  401. if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {
  402. Tcb->RttMeasure++;
  403. }
  404. Tcb->Idle++;
  405. if (Tcb->DelayedAck != 0) {
  406. TcpSendAck (Tcb);
  407. }
  408. if ((Tcb->IpInfo->IpVersion == IP_VERSION_6) && (Tcb->Tick > 0)) {
  409. Tcb->Tick--;
  410. }
  411. //
  412. // No timer is active or no timer expired
  413. //
  414. if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON) || ((--Tcb->NextExpire) > 0)) {
  415. continue;
  416. }
  417. //
  418. // Call the timeout handler for each expired timer.
  419. //
  420. for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {
  421. if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) && TCP_TIME_LEQ (Tcb->Timer[Index], mTcpTick)) {
  422. //
  423. // disable the timer before calling the handler
  424. // in case the handler enables it again.
  425. //
  426. TCP_CLEAR_TIMER (Tcb->EnabledTimer, Index);
  427. mTcpTimerHandler[Index](Tcb);
  428. //
  429. // The Tcb may have been deleted by the timer, or
  430. // no other timer is set.
  431. //
  432. if ((Next->BackLink != Entry) || (Tcb->EnabledTimer == 0)) {
  433. break;
  434. }
  435. }
  436. }
  437. //
  438. // If the Tcb still exist or some timer is set, update the timer
  439. //
  440. if (Index == TCP_TIMER_NUMBER) {
  441. TcpUpdateTimer (Tcb);
  442. }
  443. }
  444. }
  445. /**
  446. Heart beat timer handler, queues the DPC at TPL_CALLBACK.
  447. @param[in] Event Timer event signaled, ignored.
  448. @param[in] Context Context of the timer event, ignored.
  449. **/
  450. VOID
  451. EFIAPI
  452. TcpTicking (
  453. IN EFI_EVENT Event,
  454. IN VOID *Context
  455. )
  456. {
  457. QueueDpc (TPL_CALLBACK, TcpTickingDpc, Context);
  458. }