2 TCP input process routines.
4 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Check whether the sequence number of the incoming segment is acceptable.
21 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
22 @param[in] Seg Pointer to the incoming segment.
24 @retval 1 The sequence number is acceptable.
25 @retval 0 The sequence number is not acceptable.
34 return (TCP_SEQ_LEQ (Tcb
->RcvWl2
, Seg
->End
) &&
35 TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
+ Tcb
->RcvWnd
));
39 NewReno fast recovery defined in RFC3782.
41 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
42 @param[in] Seg Segment that triggers the fast recovery.
55 // Step 1: Three duplicate ACKs and not in fast recovery
57 if (Tcb
->CongestState
!= TCP_CONGEST_RECOVER
) {
60 // Step 1A: Invoking fast retransmission.
62 FlightSize
= TCP_SUB_SEQ (Tcb
->SndNxt
, Tcb
->SndUna
);
64 Tcb
->Ssthresh
= MAX (FlightSize
>> 1, (UINT32
) (2 * Tcb
->SndMss
));
65 Tcb
->Recover
= Tcb
->SndNxt
;
67 Tcb
->CongestState
= TCP_CONGEST_RECOVER
;
68 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
71 // Step 2: Entering fast retransmission
73 TcpRetransmit (Tcb
, Tcb
->SndUna
);
74 Tcb
->CWnd
= Tcb
->Ssthresh
+ 3 * Tcb
->SndMss
;
78 "TcpFastRecover: enter fast retransmission for TCB %p, recover point is %d\n",
86 // During fast recovery, execute Step 3, 4, 5 of RFC3782
88 if (Seg
->Ack
== Tcb
->SndUna
) {
91 // Step 3: Fast Recovery,
92 // If this is a duplicated ACK, increse Cwnd by SMSS.
95 // Step 4 is skipped here only to be executed later
98 Tcb
->CWnd
+= Tcb
->SndMss
;
101 "TcpFastRecover: received another duplicated ACK (%d) for TCB %p\n",
109 // New data is ACKed, check whether it is a
110 // full ACK or partial ACK
112 if (TCP_SEQ_GEQ (Seg
->Ack
, Tcb
->Recover
)) {
115 // Step 5 - Full ACK:
116 // deflate the congestion window, and exit fast recovery
118 FlightSize
= TCP_SUB_SEQ (Tcb
->SndNxt
, Tcb
->SndUna
);
120 Tcb
->CWnd
= MIN (Tcb
->Ssthresh
, FlightSize
+ Tcb
->SndMss
);
122 Tcb
->CongestState
= TCP_CONGEST_OPEN
;
125 "TcpFastRecover: received a full ACK(%d) for TCB %p, exit fast recovery\n",
133 // Step 5 - Partial ACK:
134 // fast retransmit the first unacknowledge field
135 // , then deflate the CWnd
137 TcpRetransmit (Tcb
, Seg
->Ack
);
138 Acked
= TCP_SUB_SEQ (Seg
->Ack
, Tcb
->SndUna
);
141 // Deflate the CWnd by the amount of new data
142 // ACKed by SEG.ACK. If more than one SMSS data
143 // is ACKed, add back SMSS byte to CWnd after
145 if (Acked
>= Tcb
->SndMss
) {
146 Acked
-= Tcb
->SndMss
;
154 "TcpFastRecover: received a partial ACK(%d) for TCB %p\n",
164 NewReno fast loss recovery defined in RFC3792.
166 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
167 @param[in] Seg Segment that triggers the fast loss recovery.
176 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
179 // New data is ACKed, check whether it is a
180 // full ACK or partial ACK
182 if (TCP_SEQ_GEQ (Seg
->Ack
, Tcb
->LossRecover
)) {
185 // Full ACK: exit the loss recovery.
188 Tcb
->CongestState
= TCP_CONGEST_OPEN
;
192 "TcpFastLossRecover: received a full ACK(%d) for TCB %p\n",
201 // fast retransmit the first unacknowledge field.
203 TcpRetransmit (Tcb
, Seg
->Ack
);
206 "TcpFastLossRecover: received a partial ACK(%d) for TCB %p\n",
215 Compute the RTT as specified in RFC2988.
217 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
218 @param[in] Measure Currently measured RTT in heartbeats.
230 // Step 2.3: Compute the RTO for subsequent RTT measurement.
232 if (Tcb
->SRtt
!= 0) {
234 Var
= Tcb
->SRtt
- (Measure
<< TCP_RTT_SHIFT
);
240 Tcb
->RttVar
= (3 * Tcb
->RttVar
+ Var
) >> 2;
241 Tcb
->SRtt
= 7 * (Tcb
->SRtt
>> 3) + Measure
;
245 // Step 2.2: compute the first RTT measure
247 Tcb
->SRtt
= Measure
<< TCP_RTT_SHIFT
;
248 Tcb
->RttVar
= Measure
<< (TCP_RTT_SHIFT
- 1);
251 Tcb
->Rto
= (Tcb
->SRtt
+ MAX (8, 4 * Tcb
->RttVar
)) >> TCP_RTT_SHIFT
;
254 // Step 2.4: Limit the RTO to at least 1 second
255 // Step 2.5: Limit the RTO to a maxium value that
256 // is at least 60 second
258 if (Tcb
->Rto
< TCP_RTO_MIN
) {
259 Tcb
->Rto
= TCP_RTO_MIN
;
261 } else if (Tcb
->Rto
> TCP_RTO_MAX
) {
262 Tcb
->Rto
= TCP_RTO_MAX
;
268 "TcpComputeRtt: new RTT for TCB %p computed SRTT: %d RTTVAR: %d RTO: %d\n",
278 Trim the data; SYN and FIN to fit into the window defined by Left and Right.
280 @param[in] Nbuf The buffer that contains a received TCP segment without an IP header.
281 @param[in] Left The sequence number of the window's left edge.
282 @param[in] Right The sequence number of the window's right edge.
296 Seg
= TCPSEG_NETBUF (Nbuf
);
299 // If the segment is completely out of window,
300 // truncate every thing, include SYN and FIN.
302 if (TCP_SEQ_LEQ (Seg
->End
, Left
) || TCP_SEQ_LEQ (Right
, Seg
->Seq
)) {
304 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
305 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
308 NetbufTrim (Nbuf
, Nbuf
->TotalSize
, NET_BUF_HEAD
);
313 // Adjust the buffer header
315 if (TCP_SEQ_LT (Seg
->Seq
, Left
)) {
317 Drop
= TCP_SUB_SEQ (Left
, Seg
->Seq
);
318 Urg
= Seg
->Seq
+ Seg
->Urg
;
321 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
322 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
327 // Adjust the urgent point
329 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
)) {
331 if (TCP_SEQ_LT (Urg
, Seg
->Seq
)) {
333 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_URG
);
335 Seg
->Urg
= (UINT16
) TCP_SUB_SEQ (Urg
, Seg
->Seq
);
340 NetbufTrim (Nbuf
, Drop
, NET_BUF_HEAD
);
345 // Adjust the buffer tail
347 if (TCP_SEQ_GT (Seg
->End
, Right
)) {
349 Drop
= TCP_SUB_SEQ (Seg
->End
, Right
);
352 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
353 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
358 NetbufTrim (Nbuf
, Drop
, NET_BUF_TAIL
);
362 ASSERT (TcpVerifySegment (Nbuf
) != 0);
366 Trim off the data outside the tcb's receive window.
368 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
369 @param[in] Nbuf Pointer to the NET_BUF containing the received tcp segment.
378 TcpTrimSegment (Nbuf
, Tcb
->RcvNxt
, Tcb
->RcvWl2
+ Tcb
->RcvWnd
);
382 Process the data and FIN flag, and check whether to deliver
383 data to the socket layer.
385 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
387 @retval 0 No error occurred to deliver data.
388 @retval -1 An error condition occurred. The proper response is to reset the
403 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
406 // make sure there is some data queued,
407 // and TCP is in a proper state
409 if (IsListEmpty (&Tcb
->RcvQue
) || !TCP_CONNECTED (Tcb
->State
)) {
415 // Deliver data to the socket layer
417 Entry
= Tcb
->RcvQue
.ForwardLink
;
420 while (Entry
!= &Tcb
->RcvQue
) {
421 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
422 Seg
= TCPSEG_NETBUF (Nbuf
);
424 ASSERT (TcpVerifySegment (Nbuf
) != 0);
425 ASSERT (Nbuf
->Tcp
== NULL
);
427 if (TCP_SEQ_GT (Seg
->Seq
, Seq
)) {
431 Entry
= Entry
->ForwardLink
;
435 RemoveEntryList (&Nbuf
->List
);
438 // RFC793 Eighth step: process FIN in sequence
440 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
443 // The peer sends to us junky data after FIN,
444 // reset the connection.
446 if (!IsListEmpty (&Tcb
->RcvQue
)) {
449 "TcpDeliverData: data received after FIN from peer of TCB %p, reset connection\n",
459 "TcpDeliverData: processing FIN from peer of TCB %p\n",
463 switch (Tcb
->State
) {
465 case TCP_ESTABLISHED
:
467 TcpSetState (Tcb
, TCP_CLOSE_WAIT
);
472 if (!TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
474 TcpSetState (Tcb
, TCP_CLOSING
);
483 TcpSetState (Tcb
, TCP_TIME_WAIT
);
484 TcpClearAllTimer (Tcb
);
486 if (Tcb
->TimeWaitTimeout
!= 0) {
488 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
493 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
507 // The peer sends to us junk FIN byte. Discard
508 // the buffer then reset the connection
517 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
523 // Don't delay the ack if PUSH flag is on.
525 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_PSH
)) {
527 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
530 if (Nbuf
->TotalSize
!= 0) {
533 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
534 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvUp
))
537 if (TCP_SEQ_LEQ (Seg
->End
, Tcb
->RcvUp
)) {
538 Urgent
= Nbuf
->TotalSize
;
540 Urgent
= TCP_SUB_SEQ (Tcb
->RcvUp
, Seg
->Seq
) + 1;
544 SockDataRcvd (Tcb
->Sk
, Nbuf
, Urgent
);
547 if (TCP_FIN_RCVD (Tcb
->State
)) {
549 SockNoMoreData (Tcb
->Sk
);
559 Store the data into the reassemble queue.
561 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
562 @param[in] Nbuf Pointer to the buffer containing the data to be queued.
577 ASSERT ((Tcb
!= NULL
) && (Nbuf
!= NULL
) && (Nbuf
->Tcp
== NULL
));
581 Seg
= TCPSEG_NETBUF (Nbuf
);
585 // Fast path to process normal case. That is,
586 // no out-of-order segments are received.
588 if (IsListEmpty (Head
)) {
590 InsertTailList (Head
, &Nbuf
->List
);
595 // Find the point to insert the buffer
597 for (Prev
= Head
, Cur
= Head
->ForwardLink
;
599 Prev
= Cur
, Cur
= Cur
->ForwardLink
) {
601 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
603 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
)) {
609 // Check whether the current segment overlaps with the
613 Node
= NET_LIST_USER_STRUCT (Prev
, NET_BUF
, List
);
615 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->End
)) {
617 if (TCP_SEQ_LEQ (Seg
->End
, TCPSEG_NETBUF (Node
)->End
)) {
623 TcpTrimSegment (Nbuf
, TCPSEG_NETBUF (Node
)->End
, Seg
->End
);
627 InsertHeadList (Prev
, &Nbuf
->List
);
629 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
632 // Check the segments after the insert point.
634 while (Cur
!= Head
) {
635 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
637 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->End
, Seg
->End
)) {
639 Cur
= Cur
->ForwardLink
;
641 RemoveEntryList (&Node
->List
);
646 if (TCP_SEQ_LT (TCPSEG_NETBUF (Node
)->Seq
, Seg
->End
)) {
648 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->Seq
, Seg
->Seq
)) {
650 RemoveEntryList (&Nbuf
->List
);
655 TcpTrimSegment (Nbuf
, Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
);
659 Cur
= Cur
->ForwardLink
;
665 Adjust the send queue or the retransmit queue.
667 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
668 @param[in] Ack The acknowledge seuqence number of the received segment.
683 Cur
= Head
->ForwardLink
;
685 while (Cur
!= Head
) {
686 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
687 Seg
= TCPSEG_NETBUF (Node
);
689 if (TCP_SEQ_GEQ (Seg
->Seq
, Ack
)) {
694 // Remove completely ACKed segments
696 if (TCP_SEQ_LEQ (Seg
->End
, Ack
)) {
697 Cur
= Cur
->ForwardLink
;
699 RemoveEntryList (&Node
->List
);
704 TcpTrimSegment (Node
, Ack
, Seg
->End
);
710 Process the received TCP segments.
712 @param[in] Nbuf Buffer that contains received a TCP segment without an IP header.
713 @param[in] Src Source address of the segment, or the peer's IP address.
714 @param[in] Dst Destination address of the segment, or the local end's IP
716 @param[in] Version IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
719 @retval 0 Segment processed successfully. It is either accepted or
720 discarded. However, no connection is reset by the segment.
721 @retval -1 A connection is reset by the segment.
727 IN EFI_IP_ADDRESS
*Src
,
728 IN EFI_IP_ADDRESS
*Dst
,
742 ASSERT ((Version
== IP_VERSION_4
) || (Version
== IP_VERSION_6
));
744 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
749 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
750 ASSERT (Head
!= NULL
);
751 Len
= Nbuf
->TotalSize
- (Head
->HeadLen
<< 2);
753 if ((Head
->HeadLen
< 5) || (Len
< 0)) {
755 DEBUG ((EFI_D_INFO
, "TcpInput: received a malformed packet\n"));
759 if (Version
== IP_VERSION_4
) {
760 Checksum
= NetPseudoHeadChecksum (Src
->Addr
[0], Dst
->Addr
[0], 6, 0);
762 Checksum
= NetIp6PseudoHeadChecksum (&Src
->v6
, &Dst
->v6
, 6, 0);
765 Checksum
= TcpChecksum (Nbuf
, Checksum
);
768 DEBUG ((EFI_D_ERROR
, "TcpInput: received a checksum error packet\n"));
772 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)) {
776 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_FIN
)) {
786 (BOOLEAN
) TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)
789 if ((Tcb
== NULL
) || (Tcb
->State
== TCP_CLOSED
)) {
790 DEBUG ((EFI_D_INFO
, "TcpInput: send reset because no TCB found\n"));
796 Seg
= TcpFormatNetbuf (Tcb
, Nbuf
);
799 // RFC1122 recommended reaction to illegal option
800 // (in fact, an illegal option length) is reset.
802 if (TcpParseOption (Nbuf
->Tcp
, &Option
) == -1) {
805 "TcpInput: reset the peer because of malformed option for TCB %p\n",
813 // From now on, the segment is headless
815 NetbufTrim (Nbuf
, (Head
->HeadLen
<< 2), NET_BUF_HEAD
);
819 // Process the segment in LISTEN state.
821 if (Tcb
->State
== TCP_LISTEN
) {
823 // First step: Check RST
825 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
828 "TcpInput: discard a reset segment for TCB %p in listening\n",
836 // Second step: Check ACK.
837 // Any ACK sent to TCP in LISTEN is reseted.
839 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
842 "TcpInput: send reset because of segment with ACK for TCB %p in listening\n",
850 // Third step: Check SYN
852 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
854 // create a child TCB to handle the data
858 Tcb
= TcpCloneTcb (Parent
);
862 "TcpInput: discard a segment because failed to clone a child for TCB %p\n",
871 "TcpInput: create a child for TCB %p in listening\n",
876 // init the TCB structure
878 IP6_COPY_ADDRESS (&Tcb
->LocalEnd
.Ip
, Dst
);
879 IP6_COPY_ADDRESS (&Tcb
->RemoteEnd
.Ip
, Src
);
880 Tcb
->LocalEnd
.Port
= Head
->DstPort
;
881 Tcb
->RemoteEnd
.Port
= Head
->SrcPort
;
883 TcpInitTcbLocal (Tcb
);
884 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
886 TcpSetState (Tcb
, TCP_SYN_RCVD
);
887 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
888 TcpTrimInWnd (Tcb
, Nbuf
);
895 } else if (Tcb
->State
== TCP_SYN_SENT
) {
897 // First step: Check ACK bit
899 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
) && (Seg
->Ack
!= Tcb
->Iss
+ 1)) {
903 "TcpInput: send reset because of wrong ACK received for TCB %p in SYN_SENT\n",
911 // Second step: Check RST bit
913 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
915 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
919 "TcpInput: connection reset by peer for TCB %p in SYN_SENT\n",
923 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
924 goto DROP_CONNECTION
;
929 "TcpInput: discard a reset segment because of no ACK for TCB %p in SYN_SENT\n",
938 // Third step: Check security and precedence. Skipped
942 // Fourth step: Check SYN. Pay attention to simultaneous open
944 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
946 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
948 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
950 Tcb
->SndUna
= Seg
->Ack
;
953 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
955 if (TCP_SEQ_GT (Tcb
->SndUna
, Tcb
->Iss
)) {
957 TcpSetState (Tcb
, TCP_ESTABLISHED
);
959 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
960 TcpDeliverData (Tcb
);
962 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
963 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
))
966 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
967 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
970 TcpTrimInWnd (Tcb
, Nbuf
);
972 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
976 "TcpInput: connection established for TCB %p in SYN_SENT\n",
983 // Received a SYN segment without ACK, simultanous open.
985 TcpSetState (Tcb
, TCP_SYN_RCVD
);
987 ASSERT (Tcb
->SndNxt
== Tcb
->Iss
+ 1);
988 TcpAdjustSndQue (Tcb
, Tcb
->SndNxt
);
990 TcpTrimInWnd (Tcb
, Nbuf
);
994 "TcpInput: simultaneous open for TCB %p in SYN_SENT\n",
1006 // Process segment in SYN_RCVD or TCP_CONNECTED states
1010 // Clear probe timer since the RecvWindow is opened.
1012 if (Tcb
->ProbeTimerOn
&& (Seg
->Wnd
!= 0)) {
1013 TcpClearTimer (Tcb
, TCP_TIMER_PROBE
);
1014 Tcb
->ProbeTimerOn
= FALSE
;
1018 // First step: Check whether SEG.SEQ is acceptable
1020 if (TcpSeqAcceptable (Tcb
, Seg
) == 0) {
1023 "TcpInput: sequence acceptance test failed for segment of TCB %p\n",
1027 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
1034 if ((TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
)) &&
1035 (Tcb
->RcvWl2
== Seg
->End
) &&
1036 !TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
| TCP_FLG_FIN
))
1039 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1043 // Second step: Check the RST
1045 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
1047 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset for TCB %p\n", Tcb
));
1049 if (Tcb
->State
== TCP_SYN_RCVD
) {
1051 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_REFUSED
);
1054 // This TCB comes from either a LISTEN TCB,
1055 // or active open TCB with simultanous open.
1056 // Do NOT signal user CONNECTION refused
1057 // if it comes from a LISTEN TCB.
1059 } else if ((Tcb
->State
== TCP_ESTABLISHED
) ||
1060 (Tcb
->State
== TCP_FIN_WAIT_1
) ||
1061 (Tcb
->State
== TCP_FIN_WAIT_2
) ||
1062 (Tcb
->State
== TCP_CLOSE_WAIT
))
1065 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1070 goto DROP_CONNECTION
;
1074 // Trim the data and flags.
1076 TcpTrimInWnd (Tcb
, Nbuf
);
1079 // Third step: Check security and precedence, Ignored
1083 // Fourth step: Check the SYN bit.
1085 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1089 "TcpInput: connection reset because received extra SYN for TCB %p\n",
1093 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1094 goto RESET_THEN_DROP
;
1097 // Fifth step: Check the ACK
1099 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
1102 "TcpInput: segment discard because of no ACK for connected TCB %p\n",
1108 if (Tcb
->IpInfo
->IpVersion
== IP_VERSION_6
&& Tcb
->Tick
== 0) {
1109 Tcp6RefreshNeighbor (Tcb
, Src
, TCP6_KEEP_NEIGHBOR_TIME
* TICKS_PER_SECOND
);
1110 Tcb
->Tick
= TCP6_REFRESH_NEIGHBOR_TICK
;
1114 if (Tcb
->State
== TCP_SYN_RCVD
) {
1116 if (TCP_SEQ_LT (Tcb
->SndUna
, Seg
->Ack
) &&
1117 TCP_SEQ_LEQ (Seg
->Ack
, Tcb
->SndNxt
))
1120 Tcb
->SndWnd
= Seg
->Wnd
;
1121 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1122 Tcb
->SndWl1
= Seg
->Seq
;
1123 Tcb
->SndWl2
= Seg
->Ack
;
1124 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1126 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1127 TcpDeliverData (Tcb
);
1131 "TcpInput: connection established for TCB %p in SYN_RCVD\n",
1136 // Continue the process as ESTABLISHED state
1141 "TcpInput: send reset because of wrong ACK for TCB %p in SYN_RCVD\n",
1149 if (TCP_SEQ_LT (Seg
->Ack
, Tcb
->SndUna
)) {
1153 "TcpInput: ignore the out-of-data ACK for connected TCB %p\n",
1159 } else if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndNxt
)) {
1163 "TcpInput: discard segment for future ACK for connected TCB %p\n",
1172 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1174 if (TCP_FLG_ON (Option
.Flag
, TCP_OPTION_RCVD_TS
)) {
1176 // update TsRecent as specified in page 16 RFC1323.
1177 // RcvWl2 equals to the variable "LastAckSent"
1180 if (TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
) &&
1181 TCP_SEQ_LT (Tcb
->RcvWl2
, Seg
->End
))
1184 Tcb
->TsRecent
= Option
.TSVal
;
1185 Tcb
->TsRecentAge
= mTcpTick
;
1188 TcpComputeRtt (Tcb
, TCP_SUB_TIME (mTcpTick
, Option
.TSEcr
));
1190 } else if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
1192 ASSERT (Tcb
->CongestState
== TCP_CONGEST_OPEN
);
1194 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1195 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1198 if (Seg
->Ack
== Tcb
->SndNxt
) {
1200 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1203 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
1207 // Count duplicate acks.
1209 if ((Seg
->Ack
== Tcb
->SndUna
) &&
1210 (Tcb
->SndUna
!= Tcb
->SndNxt
) &&
1211 (Seg
->Wnd
== Tcb
->SndWnd
) &&
1222 // Congestion avoidance, fast recovery and fast retransmission.
1224 if (((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && (Tcb
->DupAck
< 3)) ||
1225 (Tcb
->CongestState
== TCP_CONGEST_LOSS
))
1228 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1230 if (Tcb
->CWnd
< Tcb
->Ssthresh
) {
1232 Tcb
->CWnd
+= Tcb
->SndMss
;
1235 Tcb
->CWnd
+= MAX (Tcb
->SndMss
* Tcb
->SndMss
/ Tcb
->CWnd
, 1);
1238 Tcb
->CWnd
= MIN (Tcb
->CWnd
, TCP_MAX_WIN
<< Tcb
->SndWndScale
);
1241 if (Tcb
->CongestState
== TCP_CONGEST_LOSS
) {
1242 TcpFastLossRecover (Tcb
, Seg
);
1246 TcpFastRecover (Tcb
, Seg
);
1249 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1251 TcpAdjustSndQue (Tcb
, Seg
->Ack
);
1252 Tcb
->SndUna
= Seg
->Ack
;
1254 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
1255 TCP_SEQ_LT (Tcb
->SndUp
, Seg
->Ack
))
1258 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
1263 // Update window info
1265 if (TCP_SEQ_LT (Tcb
->SndWl1
, Seg
->Seq
) ||
1266 ((Tcb
->SndWl1
== Seg
->Seq
) && TCP_SEQ_LEQ (Tcb
->SndWl2
, Seg
->Ack
)))
1269 Right
= Seg
->Ack
+ Seg
->Wnd
;
1271 if (TCP_SEQ_LT (Right
, Tcb
->SndWl2
+ Tcb
->SndWnd
)) {
1273 if ((Tcb
->SndWl1
== Seg
->Seq
) &&
1274 (Tcb
->SndWl2
== Seg
->Ack
) &&
1283 "TcpInput: peer shrinks the window for connected TCB %p\n",
1287 if ((Tcb
->CongestState
== TCP_CONGEST_RECOVER
) &&
1288 (TCP_SEQ_LT (Right
, Tcb
->Recover
)))
1291 Tcb
->Recover
= Right
;
1294 if ((Tcb
->CongestState
== TCP_CONGEST_LOSS
) &&
1295 (TCP_SEQ_LT (Right
, Tcb
->LossRecover
)))
1298 Tcb
->LossRecover
= Right
;
1301 if (TCP_SEQ_LT (Right
, Tcb
->SndNxt
)) {
1303 Tcb
->SndNxt
= Right
;
1305 if (Right
== Tcb
->SndUna
) {
1307 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1308 TcpSetProbeTimer (Tcb
);
1313 Tcb
->SndWnd
= Seg
->Wnd
;
1314 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1315 Tcb
->SndWl1
= Seg
->Seq
;
1316 Tcb
->SndWl2
= Seg
->Ack
;
1321 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
) &&
1322 (Tcb
->SndUna
== Tcb
->SndNxt
))
1327 "TcpInput: local FIN is ACKed by peer for connected TCB %p\n",
1331 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
);
1335 // Transit the state if proper.
1337 switch (Tcb
->State
) {
1338 case TCP_FIN_WAIT_1
:
1340 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1342 TcpSetState (Tcb
, TCP_FIN_WAIT_2
);
1344 TcpClearAllTimer (Tcb
);
1345 TcpSetTimer (Tcb
, TCP_TIMER_FINWAIT2
, Tcb
->FinWait2Timeout
);
1348 case TCP_FIN_WAIT_2
:
1352 case TCP_CLOSE_WAIT
:
1357 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1359 TcpSetState (Tcb
, TCP_TIME_WAIT
);
1361 TcpClearAllTimer (Tcb
);
1363 if (Tcb
->TimeWaitTimeout
!= 0) {
1365 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1370 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1381 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1383 TcpSetState (Tcb
, TCP_CLOSED
);
1392 if (Tcb
->TimeWaitTimeout
!= 0) {
1394 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1399 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1411 // Sixth step: Check the URG bit.update the Urg point
1412 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1417 TcpSetKeepaliveTimer (Tcb
);
1419 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
) && !TCP_FIN_RCVD (Tcb
->State
)) {
1423 "TcpInput: received urgent data from peer for connected TCB %p\n",
1427 Urg
= Seg
->Seq
+ Seg
->Urg
;
1429 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
1430 TCP_SEQ_GT (Urg
, Tcb
->RcvUp
))
1437 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
);
1441 // Seventh step: Process the segment data
1443 if (Seg
->End
!= Seg
->Seq
) {
1445 if (TCP_FIN_RCVD (Tcb
->State
)) {
1449 "TcpInput: connection reset because data is lost for connected TCB %p\n",
1453 goto RESET_THEN_DROP
;
1456 if (TCP_LOCAL_CLOSED (Tcb
->State
) && (Nbuf
->TotalSize
!= 0)) {
1459 "TcpInput: connection reset because data is lost for connected TCB %p\n",
1463 goto RESET_THEN_DROP
;
1466 TcpQueueData (Tcb
, Nbuf
);
1467 if (TcpDeliverData (Tcb
) == -1) {
1468 goto RESET_THEN_DROP
;
1471 if (!IsListEmpty (&Tcb
->RcvQue
)) {
1472 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1477 // Eighth step: check the FIN.
1478 // This step is moved to TcpDeliverData. FIN will be
1479 // processed in sequence there. Check the comments in
1480 // the beginning of the file header for information.
1484 // Tcb is a new child of the listening Parent,
1487 if (Parent
!= NULL
) {
1488 Tcb
->Parent
= Parent
;
1492 if ((Tcb
->State
!= TCP_CLOSED
) &&
1493 (TcpToSendData (Tcb
, 0) == 0) &&
1494 (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || (Nbuf
->TotalSize
!= 0)))
1504 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
, Version
);
1507 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
1516 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
, Version
);
1521 // Tcb is a child of Parent, and it doesn't survive
1523 DEBUG ((EFI_D_WARN
, "TcpInput: Discard a packet\n"));
1526 if ((Parent
!= NULL
) && (Tcb
!= NULL
)) {
1528 ASSERT (Tcb
->Sk
!= NULL
);
1536 Process the received ICMP error messages for TCP.
1538 @param[in] Nbuf The buffer that contains part of the TCP segment without an IP header
1539 truncated from the ICMP error packet.
1540 @param[in] IcmpErr The ICMP error code interpreted from an ICMP error packet.
1541 @param[in] Src Source address of the ICMP error message.
1542 @param[in] Dst Destination address of the ICMP error message.
1543 @param[in] Version IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
1551 IN EFI_IP_ADDRESS
*Src
,
1552 IN EFI_IP_ADDRESS
*Dst
,
1559 EFI_STATUS IcmpErrStatus
;
1560 BOOLEAN IcmpErrIsHard
;
1561 BOOLEAN IcmpErrNotify
;
1563 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
1564 ASSERT (Head
!= NULL
);
1566 Tcb
= TcpLocateTcb (
1574 if (Tcb
== NULL
|| Tcb
->State
== TCP_CLOSED
) {
1580 // Validate the sequence number.
1582 Seq
= NTOHL (Head
->Seq
);
1583 if (!(TCP_SEQ_LEQ (Tcb
->SndUna
, Seq
) && TCP_SEQ_LT (Seq
, Tcb
->SndNxt
))) {
1588 IcmpErrStatus
= IpIoGetIcmpErrStatus (
1595 if (IcmpErrNotify
) {
1597 SOCK_ERROR (Tcb
->Sk
, IcmpErrStatus
);
1600 if (IcmpErrIsHard
) {