2 TCP input process routines.
4 Copyright (c) 2009 - 2016, 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.
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
);
752 if (Nbuf
->TotalSize
< sizeof (TCP_HEAD
)) {
753 DEBUG ((EFI_D_INFO
, "TcpInput: received a malformed packet\n"));
757 Len
= Nbuf
->TotalSize
- (Head
->HeadLen
<< 2);
759 if ((Head
->HeadLen
< 5) || (Len
< 0)) {
761 DEBUG ((EFI_D_INFO
, "TcpInput: received a malformed packet\n"));
766 if (Version
== IP_VERSION_4
) {
767 Checksum
= NetPseudoHeadChecksum (Src
->Addr
[0], Dst
->Addr
[0], 6, 0);
769 Checksum
= NetIp6PseudoHeadChecksum (&Src
->v6
, &Dst
->v6
, 6, 0);
772 Checksum
= TcpChecksum (Nbuf
, Checksum
);
775 DEBUG ((EFI_D_ERROR
, "TcpInput: received a checksum error packet\n"));
779 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)) {
783 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_FIN
)) {
793 (BOOLEAN
) TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)
796 if ((Tcb
== NULL
) || (Tcb
->State
== TCP_CLOSED
)) {
797 DEBUG ((EFI_D_INFO
, "TcpInput: send reset because no TCB found\n"));
803 Seg
= TcpFormatNetbuf (Tcb
, Nbuf
);
806 // RFC1122 recommended reaction to illegal option
807 // (in fact, an illegal option length) is reset.
809 if (TcpParseOption (Nbuf
->Tcp
, &Option
) == -1) {
812 "TcpInput: reset the peer because of malformed option for TCB %p\n",
820 // From now on, the segment is headless
822 NetbufTrim (Nbuf
, (Head
->HeadLen
<< 2), NET_BUF_HEAD
);
826 // Process the segment in LISTEN state.
828 if (Tcb
->State
== TCP_LISTEN
) {
830 // First step: Check RST
832 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
835 "TcpInput: discard a reset segment for TCB %p in listening\n",
843 // Second step: Check ACK.
844 // Any ACK sent to TCP in LISTEN is reseted.
846 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
849 "TcpInput: send reset because of segment with ACK for TCB %p in listening\n",
857 // Third step: Check SYN
859 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
861 // create a child TCB to handle the data
865 Tcb
= TcpCloneTcb (Parent
);
869 "TcpInput: discard a segment because failed to clone a child for TCB %p\n",
878 "TcpInput: create a child for TCB %p in listening\n",
883 // init the TCB structure
885 IP6_COPY_ADDRESS (&Tcb
->LocalEnd
.Ip
, Dst
);
886 IP6_COPY_ADDRESS (&Tcb
->RemoteEnd
.Ip
, Src
);
887 Tcb
->LocalEnd
.Port
= Head
->DstPort
;
888 Tcb
->RemoteEnd
.Port
= Head
->SrcPort
;
890 TcpInitTcbLocal (Tcb
);
891 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
893 TcpSetState (Tcb
, TCP_SYN_RCVD
);
894 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
895 TcpTrimInWnd (Tcb
, Nbuf
);
902 } else if (Tcb
->State
== TCP_SYN_SENT
) {
904 // First step: Check ACK bit
906 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
) && (Seg
->Ack
!= Tcb
->Iss
+ 1)) {
910 "TcpInput: send reset because of wrong ACK received for TCB %p in SYN_SENT\n",
918 // Second step: Check RST bit
920 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
922 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
926 "TcpInput: connection reset by peer for TCB %p in SYN_SENT\n",
930 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
931 goto DROP_CONNECTION
;
936 "TcpInput: discard a reset segment because of no ACK for TCB %p in SYN_SENT\n",
945 // Third step: Check security and precedence. Skipped
949 // Fourth step: Check SYN. Pay attention to simultaneous open
951 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
953 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
955 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
957 Tcb
->SndUna
= Seg
->Ack
;
960 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
962 if (TCP_SEQ_GT (Tcb
->SndUna
, Tcb
->Iss
)) {
964 TcpSetState (Tcb
, TCP_ESTABLISHED
);
966 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
967 TcpDeliverData (Tcb
);
969 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
970 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
))
973 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
974 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
977 TcpTrimInWnd (Tcb
, Nbuf
);
979 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
983 "TcpInput: connection established for TCB %p in SYN_SENT\n",
990 // Received a SYN segment without ACK, simultanous open.
992 TcpSetState (Tcb
, TCP_SYN_RCVD
);
994 ASSERT (Tcb
->SndNxt
== Tcb
->Iss
+ 1);
995 TcpAdjustSndQue (Tcb
, Tcb
->SndNxt
);
997 TcpTrimInWnd (Tcb
, Nbuf
);
1001 "TcpInput: simultaneous open for TCB %p in SYN_SENT\n",
1013 // Process segment in SYN_RCVD or TCP_CONNECTED states
1017 // Clear probe timer since the RecvWindow is opened.
1019 if (Tcb
->ProbeTimerOn
&& (Seg
->Wnd
!= 0)) {
1020 TcpClearTimer (Tcb
, TCP_TIMER_PROBE
);
1021 Tcb
->ProbeTimerOn
= FALSE
;
1025 // First step: Check whether SEG.SEQ is acceptable
1027 if (TcpSeqAcceptable (Tcb
, Seg
) == 0) {
1030 "TcpInput: sequence acceptance test failed for segment of TCB %p\n",
1034 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
1041 if ((TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
)) &&
1042 (Tcb
->RcvWl2
== Seg
->End
) &&
1043 !TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
| TCP_FLG_FIN
))
1046 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1050 // Second step: Check the RST
1052 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
1054 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset for TCB %p\n", Tcb
));
1056 if (Tcb
->State
== TCP_SYN_RCVD
) {
1058 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_REFUSED
);
1061 // This TCB comes from either a LISTEN TCB,
1062 // or active open TCB with simultanous open.
1063 // Do NOT signal user CONNECTION refused
1064 // if it comes from a LISTEN TCB.
1066 } else if ((Tcb
->State
== TCP_ESTABLISHED
) ||
1067 (Tcb
->State
== TCP_FIN_WAIT_1
) ||
1068 (Tcb
->State
== TCP_FIN_WAIT_2
) ||
1069 (Tcb
->State
== TCP_CLOSE_WAIT
))
1072 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1077 goto DROP_CONNECTION
;
1081 // Trim the data and flags.
1083 TcpTrimInWnd (Tcb
, Nbuf
);
1086 // Third step: Check security and precedence, Ignored
1090 // Fourth step: Check the SYN bit.
1092 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1096 "TcpInput: connection reset because received extra SYN for TCB %p\n",
1100 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1101 goto RESET_THEN_DROP
;
1104 // Fifth step: Check the ACK
1106 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
1109 "TcpInput: segment discard because of no ACK for connected TCB %p\n",
1115 if (Tcb
->IpInfo
->IpVersion
== IP_VERSION_6
&& Tcb
->Tick
== 0) {
1116 Tcp6RefreshNeighbor (Tcb
, Src
, TCP6_KEEP_NEIGHBOR_TIME
* TICKS_PER_SECOND
);
1117 Tcb
->Tick
= TCP6_REFRESH_NEIGHBOR_TICK
;
1121 if (Tcb
->State
== TCP_SYN_RCVD
) {
1123 if (TCP_SEQ_LT (Tcb
->SndUna
, Seg
->Ack
) &&
1124 TCP_SEQ_LEQ (Seg
->Ack
, Tcb
->SndNxt
))
1127 Tcb
->SndWnd
= Seg
->Wnd
;
1128 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1129 Tcb
->SndWl1
= Seg
->Seq
;
1130 Tcb
->SndWl2
= Seg
->Ack
;
1131 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1133 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1134 TcpDeliverData (Tcb
);
1138 "TcpInput: connection established for TCB %p in SYN_RCVD\n",
1143 // Continue the process as ESTABLISHED state
1148 "TcpInput: send reset because of wrong ACK for TCB %p in SYN_RCVD\n",
1156 if (TCP_SEQ_LT (Seg
->Ack
, Tcb
->SndUna
)) {
1160 "TcpInput: ignore the out-of-data ACK for connected TCB %p\n",
1166 } else if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndNxt
)) {
1170 "TcpInput: discard segment for future ACK for connected TCB %p\n",
1179 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1181 if (TCP_FLG_ON (Option
.Flag
, TCP_OPTION_RCVD_TS
)) {
1183 // update TsRecent as specified in page 16 RFC1323.
1184 // RcvWl2 equals to the variable "LastAckSent"
1187 if (TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
) &&
1188 TCP_SEQ_LT (Tcb
->RcvWl2
, Seg
->End
))
1191 Tcb
->TsRecent
= Option
.TSVal
;
1192 Tcb
->TsRecentAge
= mTcpTick
;
1195 TcpComputeRtt (Tcb
, TCP_SUB_TIME (mTcpTick
, Option
.TSEcr
));
1197 } else if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
1199 ASSERT (Tcb
->CongestState
== TCP_CONGEST_OPEN
);
1201 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1202 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1205 if (Seg
->Ack
== Tcb
->SndNxt
) {
1207 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1210 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
1214 // Count duplicate acks.
1216 if ((Seg
->Ack
== Tcb
->SndUna
) &&
1217 (Tcb
->SndUna
!= Tcb
->SndNxt
) &&
1218 (Seg
->Wnd
== Tcb
->SndWnd
) &&
1229 // Congestion avoidance, fast recovery and fast retransmission.
1231 if (((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && (Tcb
->DupAck
< 3)) ||
1232 (Tcb
->CongestState
== TCP_CONGEST_LOSS
))
1235 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1237 if (Tcb
->CWnd
< Tcb
->Ssthresh
) {
1239 Tcb
->CWnd
+= Tcb
->SndMss
;
1242 Tcb
->CWnd
+= MAX (Tcb
->SndMss
* Tcb
->SndMss
/ Tcb
->CWnd
, 1);
1245 Tcb
->CWnd
= MIN (Tcb
->CWnd
, TCP_MAX_WIN
<< Tcb
->SndWndScale
);
1248 if (Tcb
->CongestState
== TCP_CONGEST_LOSS
) {
1249 TcpFastLossRecover (Tcb
, Seg
);
1253 TcpFastRecover (Tcb
, Seg
);
1256 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1258 TcpAdjustSndQue (Tcb
, Seg
->Ack
);
1259 Tcb
->SndUna
= Seg
->Ack
;
1261 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
1262 TCP_SEQ_LT (Tcb
->SndUp
, Seg
->Ack
))
1265 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
1270 // Update window info
1272 if (TCP_SEQ_LT (Tcb
->SndWl1
, Seg
->Seq
) ||
1273 ((Tcb
->SndWl1
== Seg
->Seq
) && TCP_SEQ_LEQ (Tcb
->SndWl2
, Seg
->Ack
)))
1276 Right
= Seg
->Ack
+ Seg
->Wnd
;
1278 if (TCP_SEQ_LT (Right
, Tcb
->SndWl2
+ Tcb
->SndWnd
)) {
1280 if ((Tcb
->SndWl1
== Seg
->Seq
) &&
1281 (Tcb
->SndWl2
== Seg
->Ack
) &&
1290 "TcpInput: peer shrinks the window for connected TCB %p\n",
1294 if ((Tcb
->CongestState
== TCP_CONGEST_RECOVER
) &&
1295 (TCP_SEQ_LT (Right
, Tcb
->Recover
)))
1298 Tcb
->Recover
= Right
;
1301 if ((Tcb
->CongestState
== TCP_CONGEST_LOSS
) &&
1302 (TCP_SEQ_LT (Right
, Tcb
->LossRecover
)))
1305 Tcb
->LossRecover
= Right
;
1308 if (TCP_SEQ_LT (Right
, Tcb
->SndNxt
)) {
1310 Tcb
->SndNxt
= Right
;
1312 if (Right
== Tcb
->SndUna
) {
1314 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1315 TcpSetProbeTimer (Tcb
);
1320 Tcb
->SndWnd
= Seg
->Wnd
;
1321 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1322 Tcb
->SndWl1
= Seg
->Seq
;
1323 Tcb
->SndWl2
= Seg
->Ack
;
1328 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
) &&
1329 (Tcb
->SndUna
== Tcb
->SndNxt
))
1334 "TcpInput: local FIN is ACKed by peer for connected TCB %p\n",
1338 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
);
1342 // Transit the state if proper.
1344 switch (Tcb
->State
) {
1345 case TCP_FIN_WAIT_1
:
1347 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1349 TcpSetState (Tcb
, TCP_FIN_WAIT_2
);
1351 TcpClearAllTimer (Tcb
);
1352 TcpSetTimer (Tcb
, TCP_TIMER_FINWAIT2
, Tcb
->FinWait2Timeout
);
1355 case TCP_FIN_WAIT_2
:
1359 case TCP_CLOSE_WAIT
:
1364 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1366 TcpSetState (Tcb
, TCP_TIME_WAIT
);
1368 TcpClearAllTimer (Tcb
);
1370 if (Tcb
->TimeWaitTimeout
!= 0) {
1372 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1377 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1388 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1390 TcpSetState (Tcb
, TCP_CLOSED
);
1399 if (Tcb
->TimeWaitTimeout
!= 0) {
1401 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1406 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1418 // Sixth step: Check the URG bit.update the Urg point
1419 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1424 TcpSetKeepaliveTimer (Tcb
);
1426 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
) && !TCP_FIN_RCVD (Tcb
->State
)) {
1430 "TcpInput: received urgent data from peer for connected TCB %p\n",
1434 Urg
= Seg
->Seq
+ Seg
->Urg
;
1436 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
1437 TCP_SEQ_GT (Urg
, Tcb
->RcvUp
))
1444 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
);
1448 // Seventh step: Process the segment data
1450 if (Seg
->End
!= Seg
->Seq
) {
1452 if (TCP_FIN_RCVD (Tcb
->State
)) {
1456 "TcpInput: connection reset because data is lost for connected TCB %p\n",
1460 goto RESET_THEN_DROP
;
1463 if (TCP_LOCAL_CLOSED (Tcb
->State
) && (Nbuf
->TotalSize
!= 0)) {
1466 "TcpInput: connection reset because data is lost for connected TCB %p\n",
1470 goto RESET_THEN_DROP
;
1473 TcpQueueData (Tcb
, Nbuf
);
1474 if (TcpDeliverData (Tcb
) == -1) {
1475 goto RESET_THEN_DROP
;
1478 if (!IsListEmpty (&Tcb
->RcvQue
)) {
1479 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1484 // Eighth step: check the FIN.
1485 // This step is moved to TcpDeliverData. FIN will be
1486 // processed in sequence there. Check the comments in
1487 // the beginning of the file header for information.
1491 // Tcb is a new child of the listening Parent,
1494 if (Parent
!= NULL
) {
1495 Tcb
->Parent
= Parent
;
1499 if ((Tcb
->State
!= TCP_CLOSED
) &&
1500 (TcpToSendData (Tcb
, 0) == 0) &&
1501 (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || (Nbuf
->TotalSize
!= 0)))
1511 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
, Version
);
1514 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
1523 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
, Version
);
1528 // Tcb is a child of Parent, and it doesn't survive
1530 DEBUG ((EFI_D_WARN
, "TcpInput: Discard a packet\n"));
1533 if ((Parent
!= NULL
) && (Tcb
!= NULL
)) {
1535 ASSERT (Tcb
->Sk
!= NULL
);
1543 Process the received ICMP error messages for TCP.
1545 @param[in] Nbuf The buffer that contains part of the TCP segment without an IP header
1546 truncated from the ICMP error packet.
1547 @param[in] IcmpErr The ICMP error code interpreted from an ICMP error packet.
1548 @param[in] Src Source address of the ICMP error message.
1549 @param[in] Dst Destination address of the ICMP error message.
1550 @param[in] Version IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
1558 IN EFI_IP_ADDRESS
*Src
,
1559 IN EFI_IP_ADDRESS
*Dst
,
1566 EFI_STATUS IcmpErrStatus
;
1567 BOOLEAN IcmpErrIsHard
;
1568 BOOLEAN IcmpErrNotify
;
1570 if (Nbuf
->TotalSize
< sizeof (TCP_HEAD
)) {
1574 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
1575 ASSERT (Head
!= NULL
);
1577 Tcb
= TcpLocateTcb (
1585 if (Tcb
== NULL
|| Tcb
->State
== TCP_CLOSED
) {
1591 // Validate the sequence number.
1593 Seq
= NTOHL (Head
->Seq
);
1594 if (!(TCP_SEQ_LEQ (Tcb
->SndUna
, Seq
) && TCP_SEQ_LT (Seq
, Tcb
->SndNxt
))) {
1599 IcmpErrStatus
= IpIoGetIcmpErrStatus (
1606 if (IcmpErrNotify
) {
1608 SOCK_ERROR (Tcb
->Sk
, IcmpErrStatus
);
1611 if (IcmpErrIsHard
) {