2 TCP input process routines.
4 Copyright (c) 2009 - 2017, 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
->RcvNxt
, 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.
284 @retval 0 The segment is broken.
285 @retval 1 The segment is in good shape.
299 Seg
= TCPSEG_NETBUF (Nbuf
);
302 // If the segment is completely out of window,
303 // truncate every thing, include SYN and FIN.
305 if (TCP_SEQ_LEQ (Seg
->End
, Left
) || TCP_SEQ_LEQ (Right
, Seg
->Seq
)) {
307 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
308 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
311 NetbufTrim (Nbuf
, Nbuf
->TotalSize
, NET_BUF_HEAD
);
316 // Adjust the buffer header
318 if (TCP_SEQ_LT (Seg
->Seq
, Left
)) {
320 Drop
= TCP_SUB_SEQ (Left
, Seg
->Seq
);
321 Urg
= Seg
->Seq
+ Seg
->Urg
;
324 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
325 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
330 // Adjust the urgent point
332 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
)) {
334 if (TCP_SEQ_LT (Urg
, Seg
->Seq
)) {
336 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_URG
);
338 Seg
->Urg
= (UINT16
) TCP_SUB_SEQ (Urg
, Seg
->Seq
);
343 NetbufTrim (Nbuf
, Drop
, NET_BUF_HEAD
);
348 // Adjust the buffer tail
350 if (TCP_SEQ_GT (Seg
->End
, Right
)) {
352 Drop
= TCP_SUB_SEQ (Seg
->End
, Right
);
355 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
356 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
361 NetbufTrim (Nbuf
, Drop
, NET_BUF_TAIL
);
365 return TcpVerifySegment (Nbuf
);
369 Trim off the data outside the tcb's receive window.
371 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
372 @param[in] Nbuf Pointer to the NET_BUF containing the received tcp segment.
374 @retval 0 The segment is broken.
375 @retval 1 The segment is in good shape.
384 return TcpTrimSegment (Nbuf
, Tcb
->RcvNxt
, Tcb
->RcvWl2
+ Tcb
->RcvWnd
);
388 Process the data and FIN flag, and check whether to deliver
389 data to the socket layer.
391 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
393 @retval 0 No error occurred to deliver data.
394 @retval -1 An error condition occurred. The proper response is to reset the
409 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
412 // make sure there is some data queued,
413 // and TCP is in a proper state
415 if (IsListEmpty (&Tcb
->RcvQue
) || !TCP_CONNECTED (Tcb
->State
)) {
421 // Deliver data to the socket layer
423 Entry
= Tcb
->RcvQue
.ForwardLink
;
426 while (Entry
!= &Tcb
->RcvQue
) {
427 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
428 Seg
= TCPSEG_NETBUF (Nbuf
);
430 if (TcpVerifySegment (Nbuf
) == 0) {
433 "TcpToSendData: discard a broken segment for TCB %p\n",
440 ASSERT (Nbuf
->Tcp
== NULL
);
442 if (TCP_SEQ_GT (Seg
->Seq
, Seq
)) {
446 Entry
= Entry
->ForwardLink
;
450 RemoveEntryList (&Nbuf
->List
);
453 // RFC793 Eighth step: process FIN in sequence
455 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
458 // The peer sends to us junky data after FIN,
459 // reset the connection.
461 if (!IsListEmpty (&Tcb
->RcvQue
)) {
464 "TcpDeliverData: data received after FIN from peer of TCB %p, reset connection\n",
474 "TcpDeliverData: processing FIN from peer of TCB %p\n",
478 switch (Tcb
->State
) {
480 case TCP_ESTABLISHED
:
482 TcpSetState (Tcb
, TCP_CLOSE_WAIT
);
487 if (!TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
489 TcpSetState (Tcb
, TCP_CLOSING
);
498 TcpSetState (Tcb
, TCP_TIME_WAIT
);
499 TcpClearAllTimer (Tcb
);
501 if (Tcb
->TimeWaitTimeout
!= 0) {
503 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
508 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
522 // The peer sends to us junk FIN byte. Discard
523 // the buffer then reset the connection
532 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
538 // Don't delay the ack if PUSH flag is on.
540 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_PSH
)) {
542 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
545 if (Nbuf
->TotalSize
!= 0) {
548 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
549 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvUp
))
552 if (TCP_SEQ_LEQ (Seg
->End
, Tcb
->RcvUp
)) {
553 Urgent
= Nbuf
->TotalSize
;
555 Urgent
= TCP_SUB_SEQ (Tcb
->RcvUp
, Seg
->Seq
) + 1;
559 SockDataRcvd (Tcb
->Sk
, Nbuf
, Urgent
);
562 if (TCP_FIN_RCVD (Tcb
->State
)) {
564 SockNoMoreData (Tcb
->Sk
);
574 Store the data into the reassemble queue.
576 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
577 @param[in] Nbuf Pointer to the buffer containing the data to be queued.
579 @retval 0 An error condition occurred.
580 @retval 1 No error occurred to queue data.
595 ASSERT ((Tcb
!= NULL
) && (Nbuf
!= NULL
) && (Nbuf
->Tcp
== NULL
));
599 Seg
= TCPSEG_NETBUF (Nbuf
);
603 // Fast path to process normal case. That is,
604 // no out-of-order segments are received.
606 if (IsListEmpty (Head
)) {
608 InsertTailList (Head
, &Nbuf
->List
);
613 // Find the point to insert the buffer
615 for (Prev
= Head
, Cur
= Head
->ForwardLink
;
617 Prev
= Cur
, Cur
= Cur
->ForwardLink
) {
619 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
621 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
)) {
627 // Check whether the current segment overlaps with the
631 Node
= NET_LIST_USER_STRUCT (Prev
, NET_BUF
, List
);
633 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->End
)) {
635 if (TCP_SEQ_LEQ (Seg
->End
, TCPSEG_NETBUF (Node
)->End
)) {
639 if (TcpTrimSegment (Nbuf
, TCPSEG_NETBUF (Node
)->End
, Seg
->End
) == 0) {
645 InsertHeadList (Prev
, &Nbuf
->List
);
647 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
650 // Check the segments after the insert point.
652 while (Cur
!= Head
) {
653 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
655 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->End
, Seg
->End
)) {
657 Cur
= Cur
->ForwardLink
;
659 RemoveEntryList (&Node
->List
);
664 if (TCP_SEQ_LT (TCPSEG_NETBUF (Node
)->Seq
, Seg
->End
)) {
666 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->Seq
, Seg
->Seq
)) {
668 RemoveEntryList (&Nbuf
->List
);
672 if (TcpTrimSegment (Nbuf
, Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
) == 0) {
673 RemoveEntryList (&Nbuf
->List
);
679 Cur
= Cur
->ForwardLink
;
687 Adjust the send queue or the retransmit queue.
689 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
690 @param[in] Ack The acknowledge seuqence number of the received segment.
692 @retval 0 An error condition occurred.
693 @retval 1 No error occurred.
708 Cur
= Head
->ForwardLink
;
710 while (Cur
!= Head
) {
711 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
712 Seg
= TCPSEG_NETBUF (Node
);
714 if (TCP_SEQ_GEQ (Seg
->Seq
, Ack
)) {
719 // Remove completely ACKed segments
721 if (TCP_SEQ_LEQ (Seg
->End
, Ack
)) {
722 Cur
= Cur
->ForwardLink
;
724 RemoveEntryList (&Node
->List
);
729 return TcpTrimSegment (Node
, Ack
, Seg
->End
);
736 Process the received TCP segments.
738 @param[in] Nbuf Buffer that contains received a TCP segment without an IP header.
739 @param[in] Src Source address of the segment, or the peer's IP address.
740 @param[in] Dst Destination address of the segment, or the local end's IP
742 @param[in] Version IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
745 @retval 0 Segment processed successfully. It is either accepted or
746 discarded. However, no connection is reset by the segment.
747 @retval -1 A connection is reset by the segment.
753 IN EFI_IP_ADDRESS
*Src
,
754 IN EFI_IP_ADDRESS
*Dst
,
769 ASSERT ((Version
== IP_VERSION_4
) || (Version
== IP_VERSION_6
));
771 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
776 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
777 ASSERT (Head
!= NULL
);
779 if (Nbuf
->TotalSize
< sizeof (TCP_HEAD
)) {
780 DEBUG ((EFI_D_NET
, "TcpInput: received a malformed packet\n"));
784 Len
= Nbuf
->TotalSize
- (Head
->HeadLen
<< 2);
786 if ((Head
->HeadLen
< 5) || (Len
< 0)) {
788 DEBUG ((EFI_D_NET
, "TcpInput: received a malformed packet\n"));
793 if (Version
== IP_VERSION_4
) {
794 Checksum
= NetPseudoHeadChecksum (Src
->Addr
[0], Dst
->Addr
[0], 6, 0);
796 Checksum
= NetIp6PseudoHeadChecksum (&Src
->v6
, &Dst
->v6
, 6, 0);
799 Checksum
= TcpChecksum (Nbuf
, Checksum
);
802 DEBUG ((EFI_D_ERROR
, "TcpInput: received a checksum error packet\n"));
806 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)) {
810 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_FIN
)) {
820 (BOOLEAN
) TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)
823 if ((Tcb
== NULL
) || (Tcb
->State
== TCP_CLOSED
)) {
824 DEBUG ((EFI_D_NET
, "TcpInput: send reset because no TCB found\n"));
830 Seg
= TcpFormatNetbuf (Tcb
, Nbuf
);
833 // RFC1122 recommended reaction to illegal option
834 // (in fact, an illegal option length) is reset.
836 if (TcpParseOption (Nbuf
->Tcp
, &Option
) == -1) {
839 "TcpInput: reset the peer because of malformed option for TCB %p\n",
847 // From now on, the segment is headless
849 NetbufTrim (Nbuf
, (Head
->HeadLen
<< 2), NET_BUF_HEAD
);
853 // Process the segment in LISTEN state.
855 if (Tcb
->State
== TCP_LISTEN
) {
857 // First step: Check RST
859 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
862 "TcpInput: discard a reset segment for TCB %p in listening\n",
870 // Second step: Check ACK.
871 // Any ACK sent to TCP in LISTEN is reseted.
873 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
876 "TcpInput: send reset because of segment with ACK for TCB %p in listening\n",
884 // Third step: Check SYN
886 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
888 // create a child TCB to handle the data
892 Tcb
= TcpCloneTcb (Parent
);
896 "TcpInput: discard a segment because failed to clone a child for TCB %p\n",
905 "TcpInput: create a child for TCB %p in listening\n",
910 // init the TCB structure
912 IP6_COPY_ADDRESS (&Tcb
->LocalEnd
.Ip
, Dst
);
913 IP6_COPY_ADDRESS (&Tcb
->RemoteEnd
.Ip
, Src
);
914 Tcb
->LocalEnd
.Port
= Head
->DstPort
;
915 Tcb
->RemoteEnd
.Port
= Head
->SrcPort
;
917 TcpInitTcbLocal (Tcb
);
918 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
920 TcpSetState (Tcb
, TCP_SYN_RCVD
);
921 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
922 if (TcpTrimInWnd (Tcb
, Nbuf
) == 0) {
925 "TcpInput: discard a broken segment for TCB %p\n",
937 } else if (Tcb
->State
== TCP_SYN_SENT
) {
939 // First step: Check ACK bit
941 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
) && (Seg
->Ack
!= Tcb
->Iss
+ 1)) {
945 "TcpInput: send reset because of wrong ACK received for TCB %p in SYN_SENT\n",
953 // Second step: Check RST bit
955 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
957 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
961 "TcpInput: connection reset by peer for TCB %p in SYN_SENT\n",
965 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
966 goto DROP_CONNECTION
;
971 "TcpInput: discard a reset segment because of no ACK for TCB %p in SYN_SENT\n",
980 // Third step: Check security and precedence. Skipped
984 // Fourth step: Check SYN. Pay attention to simultaneous open
986 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
988 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
990 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
992 Tcb
->SndUna
= Seg
->Ack
;
995 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
997 if (TCP_SEQ_GT (Tcb
->SndUna
, Tcb
->Iss
)) {
999 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1001 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1002 TcpDeliverData (Tcb
);
1004 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
1005 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
))
1008 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1009 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1012 if (TcpTrimInWnd (Tcb
, Nbuf
) == 0) {
1015 "TcpInput: discard a broken segment for TCB %p\n",
1022 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1026 "TcpInput: connection established for TCB %p in SYN_SENT\n",
1033 // Received a SYN segment without ACK, simultanous open.
1035 TcpSetState (Tcb
, TCP_SYN_RCVD
);
1037 ASSERT (Tcb
->SndNxt
== Tcb
->Iss
+ 1);
1039 if (TcpAdjustSndQue (Tcb
, Tcb
->SndNxt
) == 0 || TcpTrimInWnd (Tcb
, Nbuf
) == 0) {
1042 "TcpInput: discard a broken segment for TCB %p\n",
1051 "TcpInput: simultaneous open for TCB %p in SYN_SENT\n",
1063 // Process segment in SYN_RCVD or TCP_CONNECTED states
1067 // Clear probe timer since the RecvWindow is opened.
1069 if (Tcb
->ProbeTimerOn
&& (Seg
->Wnd
!= 0)) {
1070 TcpClearTimer (Tcb
, TCP_TIMER_PROBE
);
1071 Tcb
->ProbeTimerOn
= FALSE
;
1075 // First step: Check whether SEG.SEQ is acceptable
1077 if (TcpSeqAcceptable (Tcb
, Seg
) == 0) {
1080 "TcpInput: sequence acceptance test failed for segment of TCB %p\n",
1084 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
1091 if ((TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
)) &&
1092 (Tcb
->RcvWl2
== Seg
->End
) &&
1093 !TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
| TCP_FLG_FIN
))
1096 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1100 // Second step: Check the RST
1102 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
1104 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset for TCB %p\n", Tcb
));
1106 if (Tcb
->State
== TCP_SYN_RCVD
) {
1108 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_REFUSED
);
1111 // This TCB comes from either a LISTEN TCB,
1112 // or active open TCB with simultanous open.
1113 // Do NOT signal user CONNECTION refused
1114 // if it comes from a LISTEN TCB.
1116 } else if ((Tcb
->State
== TCP_ESTABLISHED
) ||
1117 (Tcb
->State
== TCP_FIN_WAIT_1
) ||
1118 (Tcb
->State
== TCP_FIN_WAIT_2
) ||
1119 (Tcb
->State
== TCP_CLOSE_WAIT
))
1122 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1127 goto DROP_CONNECTION
;
1131 // Trim the data and flags.
1133 if (TcpTrimInWnd (Tcb
, Nbuf
) == 0) {
1136 "TcpInput: discard a broken segment for TCB %p\n",
1144 // Third step: Check security and precedence, Ignored
1148 // Fourth step: Check the SYN bit.
1150 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1154 "TcpInput: connection reset because received extra SYN for TCB %p\n",
1158 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1159 goto RESET_THEN_DROP
;
1162 // Fifth step: Check the ACK
1164 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
1167 "TcpInput: segment discard because of no ACK for connected TCB %p\n",
1173 if (Tcb
->IpInfo
->IpVersion
== IP_VERSION_6
&& Tcb
->Tick
== 0) {
1174 Tcp6RefreshNeighbor (Tcb
, Src
, TCP6_KEEP_NEIGHBOR_TIME
* TICKS_PER_SECOND
);
1175 Tcb
->Tick
= TCP6_REFRESH_NEIGHBOR_TICK
;
1179 if (Tcb
->State
== TCP_SYN_RCVD
) {
1181 if (TCP_SEQ_LT (Tcb
->SndUna
, Seg
->Ack
) &&
1182 TCP_SEQ_LEQ (Seg
->Ack
, Tcb
->SndNxt
))
1185 Tcb
->SndWnd
= Seg
->Wnd
;
1186 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1187 Tcb
->SndWl1
= Seg
->Seq
;
1188 Tcb
->SndWl2
= Seg
->Ack
;
1189 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1191 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1192 TcpDeliverData (Tcb
);
1196 "TcpInput: connection established for TCB %p in SYN_RCVD\n",
1201 // Continue the process as ESTABLISHED state
1206 "TcpInput: send reset because of wrong ACK for TCB %p in SYN_RCVD\n",
1214 if (TCP_SEQ_LT (Seg
->Ack
, Tcb
->SndUna
)) {
1218 "TcpInput: ignore the out-of-data ACK for connected TCB %p\n",
1224 } else if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndNxt
)) {
1228 "TcpInput: discard segment for future ACK for connected TCB %p\n",
1237 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1239 if (TCP_FLG_ON (Option
.Flag
, TCP_OPTION_RCVD_TS
)) {
1241 // update TsRecent as specified in page 16 RFC1323.
1242 // RcvWl2 equals to the variable "LastAckSent"
1245 if (TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
) &&
1246 TCP_SEQ_LT (Tcb
->RcvWl2
, Seg
->End
))
1249 Tcb
->TsRecent
= Option
.TSVal
;
1250 Tcb
->TsRecentAge
= mTcpTick
;
1253 TcpComputeRtt (Tcb
, TCP_SUB_TIME (mTcpTick
, Option
.TSEcr
));
1255 } else if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
1257 ASSERT (Tcb
->CongestState
== TCP_CONGEST_OPEN
);
1259 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1260 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1263 if (Seg
->Ack
== Tcb
->SndNxt
) {
1265 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1268 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
1272 // Count duplicate acks.
1274 if ((Seg
->Ack
== Tcb
->SndUna
) &&
1275 (Tcb
->SndUna
!= Tcb
->SndNxt
) &&
1276 (Seg
->Wnd
== Tcb
->SndWnd
) &&
1287 // Congestion avoidance, fast recovery and fast retransmission.
1289 if (((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && (Tcb
->DupAck
< 3)) ||
1290 (Tcb
->CongestState
== TCP_CONGEST_LOSS
))
1293 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1295 if (Tcb
->CWnd
< Tcb
->Ssthresh
) {
1297 Tcb
->CWnd
+= Tcb
->SndMss
;
1300 Tcb
->CWnd
+= MAX (Tcb
->SndMss
* Tcb
->SndMss
/ Tcb
->CWnd
, 1);
1303 Tcb
->CWnd
= MIN (Tcb
->CWnd
, TCP_MAX_WIN
<< Tcb
->SndWndScale
);
1306 if (Tcb
->CongestState
== TCP_CONGEST_LOSS
) {
1307 TcpFastLossRecover (Tcb
, Seg
);
1311 TcpFastRecover (Tcb
, Seg
);
1314 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1316 if (TcpAdjustSndQue (Tcb
, Seg
->Ack
) == 0) {
1319 "TcpInput: discard a broken segment for TCB %p\n",
1326 Tcb
->SndUna
= Seg
->Ack
;
1328 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
1329 TCP_SEQ_LT (Tcb
->SndUp
, Seg
->Ack
))
1332 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
1337 // Update window info
1339 if (TCP_SEQ_LT (Tcb
->SndWl1
, Seg
->Seq
) ||
1340 ((Tcb
->SndWl1
== Seg
->Seq
) && TCP_SEQ_LEQ (Tcb
->SndWl2
, Seg
->Ack
)))
1343 Right
= Seg
->Ack
+ Seg
->Wnd
;
1345 if (TCP_SEQ_LT (Right
, Tcb
->SndWl2
+ Tcb
->SndWnd
)) {
1347 if ((Tcb
->SndWl1
== Seg
->Seq
) &&
1348 (Tcb
->SndWl2
== Seg
->Ack
) &&
1357 "TcpInput: peer shrinks the window for connected TCB %p\n",
1361 if ((Tcb
->CongestState
== TCP_CONGEST_RECOVER
) &&
1362 (TCP_SEQ_LT (Right
, Tcb
->Recover
)))
1365 Tcb
->Recover
= Right
;
1368 if ((Tcb
->CongestState
== TCP_CONGEST_LOSS
) &&
1369 (TCP_SEQ_LT (Right
, Tcb
->LossRecover
)))
1372 Tcb
->LossRecover
= Right
;
1375 if (TCP_SEQ_LT (Right
, Tcb
->SndNxt
)) {
1377 // Check for Window Retraction in RFC7923 section 2.4.
1378 // The lower n bits of the peer's actual receive window is wiped out if TCP
1379 // window scale is enabled, it will look like the peer is shrinking the window.
1380 // Check whether the SndNxt is out of the advertised receive window by more than
1381 // 2^Rcv.Wind.Shift before moving the SndNxt to the left.
1385 "TcpInput: peer advise negative useable window for connected TCB %p\n",
1388 Usable
= TCP_SUB_SEQ (Tcb
->SndNxt
, Right
);
1389 if ((Usable
>> Tcb
->SndWndScale
) > 0) {
1392 "TcpInput: SndNxt is out of window by more than window scale for TCB %p\n",
1395 Tcb
->SndNxt
= Right
;
1397 if (Right
== Tcb
->SndUna
) {
1399 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1400 TcpSetProbeTimer (Tcb
);
1405 Tcb
->SndWnd
= Seg
->Wnd
;
1406 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1407 Tcb
->SndWl1
= Seg
->Seq
;
1408 Tcb
->SndWl2
= Seg
->Ack
;
1413 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
) &&
1414 (Tcb
->SndUna
== Tcb
->SndNxt
))
1419 "TcpInput: local FIN is ACKed by peer for connected TCB %p\n",
1423 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
);
1427 // Transit the state if proper.
1429 switch (Tcb
->State
) {
1430 case TCP_FIN_WAIT_1
:
1432 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1434 TcpSetState (Tcb
, TCP_FIN_WAIT_2
);
1436 TcpClearAllTimer (Tcb
);
1437 TcpSetTimer (Tcb
, TCP_TIMER_FINWAIT2
, Tcb
->FinWait2Timeout
);
1440 case TCP_FIN_WAIT_2
:
1444 case TCP_CLOSE_WAIT
:
1449 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1451 TcpSetState (Tcb
, TCP_TIME_WAIT
);
1453 TcpClearAllTimer (Tcb
);
1455 if (Tcb
->TimeWaitTimeout
!= 0) {
1457 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1462 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1473 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1475 TcpSetState (Tcb
, TCP_CLOSED
);
1484 if (Tcb
->TimeWaitTimeout
!= 0) {
1486 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1491 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1503 // Sixth step: Check the URG bit.update the Urg point
1504 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1509 TcpSetKeepaliveTimer (Tcb
);
1511 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
) && !TCP_FIN_RCVD (Tcb
->State
)) {
1515 "TcpInput: received urgent data from peer for connected TCB %p\n",
1519 Urg
= Seg
->Seq
+ Seg
->Urg
;
1521 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
1522 TCP_SEQ_GT (Urg
, Tcb
->RcvUp
))
1529 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
);
1533 // Seventh step: Process the segment data
1535 if (Seg
->End
!= Seg
->Seq
) {
1537 if (TCP_FIN_RCVD (Tcb
->State
)) {
1541 "TcpInput: connection reset because data is lost for connected TCB %p\n",
1545 goto RESET_THEN_DROP
;
1548 if (TCP_LOCAL_CLOSED (Tcb
->State
) && (Nbuf
->TotalSize
!= 0)) {
1551 "TcpInput: connection reset because data is lost for connected TCB %p\n",
1555 goto RESET_THEN_DROP
;
1558 if (TcpQueueData (Tcb
, Nbuf
) == 0) {
1561 "TcpInput: discard a broken segment for TCB %p\n",
1568 if (TcpDeliverData (Tcb
) == -1) {
1569 goto RESET_THEN_DROP
;
1572 if (!IsListEmpty (&Tcb
->RcvQue
)) {
1573 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1578 // Eighth step: check the FIN.
1579 // This step is moved to TcpDeliverData. FIN will be
1580 // processed in sequence there. Check the comments in
1581 // the beginning of the file header for information.
1585 // Tcb is a new child of the listening Parent,
1588 if (Parent
!= NULL
) {
1589 Tcb
->Parent
= Parent
;
1593 if ((Tcb
->State
!= TCP_CLOSED
) &&
1594 (TcpToSendData (Tcb
, 0) == 0) &&
1595 (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || (Nbuf
->TotalSize
!= 0)))
1605 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
, Version
);
1608 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
1617 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
, Version
);
1622 // Tcb is a child of Parent, and it doesn't survive
1624 DEBUG ((EFI_D_WARN
, "TcpInput: Discard a packet\n"));
1627 if ((Parent
!= NULL
) && (Tcb
!= NULL
)) {
1629 ASSERT (Tcb
->Sk
!= NULL
);
1637 Process the received ICMP error messages for TCP.
1639 @param[in] Nbuf The buffer that contains part of the TCP segment without an IP header
1640 truncated from the ICMP error packet.
1641 @param[in] IcmpErr The ICMP error code interpreted from an ICMP error packet.
1642 @param[in] Src Source address of the ICMP error message.
1643 @param[in] Dst Destination address of the ICMP error message.
1644 @param[in] Version IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
1652 IN EFI_IP_ADDRESS
*Src
,
1653 IN EFI_IP_ADDRESS
*Dst
,
1660 EFI_STATUS IcmpErrStatus
;
1661 BOOLEAN IcmpErrIsHard
;
1662 BOOLEAN IcmpErrNotify
;
1664 if (Nbuf
->TotalSize
< sizeof (TCP_HEAD
)) {
1668 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
1669 ASSERT (Head
!= NULL
);
1671 Tcb
= TcpLocateTcb (
1679 if (Tcb
== NULL
|| Tcb
->State
== TCP_CLOSED
) {
1685 // Validate the sequence number.
1687 Seq
= NTOHL (Head
->Seq
);
1688 if (!(TCP_SEQ_LEQ (Tcb
->SndUna
, Seq
) && TCP_SEQ_LT (Seq
, Tcb
->SndNxt
))) {
1693 IcmpErrStatus
= IpIoGetIcmpErrStatus (
1700 if (IcmpErrNotify
) {
1702 SOCK_ERROR (Tcb
->Sk
, IcmpErrStatus
);
1705 if (IcmpErrIsHard
) {