2 TCP input process routines.
4 Copyright (c) 2009 - 2010, 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
602 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
604 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
)) {
610 // Check whether the current segment overlaps with the
614 Node
= NET_LIST_USER_STRUCT (Prev
, NET_BUF
, List
);
616 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->End
)) {
618 if (TCP_SEQ_LEQ (Seg
->End
, TCPSEG_NETBUF (Node
)->End
)) {
624 TcpTrimSegment (Nbuf
, TCPSEG_NETBUF (Node
)->End
, Seg
->End
);
628 InsertHeadList (Prev
, &Nbuf
->List
);
630 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
633 // Check the segments after the insert point.
635 while (Cur
!= Head
) {
636 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
638 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->End
, Seg
->End
)) {
640 Cur
= Cur
->ForwardLink
;
642 RemoveEntryList (&Node
->List
);
647 if (TCP_SEQ_LT (TCPSEG_NETBUF (Node
)->Seq
, Seg
->End
)) {
649 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->Seq
, Seg
->Seq
)) {
651 RemoveEntryList (&Nbuf
->List
);
656 TcpTrimSegment (Nbuf
, Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
);
660 Cur
= Cur
->ForwardLink
;
666 Adjust the send queue or the retransmit queue.
668 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
669 @param[in] Ack The acknowledge seuqence number of the received segment.
684 Cur
= Head
->ForwardLink
;
686 while (Cur
!= Head
) {
687 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
688 Seg
= TCPSEG_NETBUF (Node
);
690 if (TCP_SEQ_GEQ (Seg
->Seq
, Ack
)) {
695 // Remove completely ACKed segments
697 if (TCP_SEQ_LEQ (Seg
->End
, Ack
)) {
698 Cur
= Cur
->ForwardLink
;
700 RemoveEntryList (&Node
->List
);
705 TcpTrimSegment (Node
, Ack
, Seg
->End
);
711 Process the received TCP segments.
713 @param[in] Nbuf Buffer that contains received a TCP segment without an IP header.
714 @param[in] Src Source address of the segment, or the peer's IP address.
715 @param[in] Dst Destination address of the segment, or the local end's IP
717 @param[in] Version IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
720 @retval 0 Segment processed successfully. It is either accepted or
721 discarded. However, no connection is reset by the segment.
722 @retval -1 A connection is reset by the segment.
728 IN EFI_IP_ADDRESS
*Src
,
729 IN EFI_IP_ADDRESS
*Dst
,
743 ASSERT ((Version
== IP_VERSION_4
) || (Version
== IP_VERSION_6
));
745 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
750 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
751 ASSERT (Head
!= NULL
);
752 Len
= Nbuf
->TotalSize
- (Head
->HeadLen
<< 2);
754 if ((Head
->HeadLen
< 5) || (Len
< 0)) {
756 DEBUG ((EFI_D_INFO
, "TcpInput: received an mal-formated packet\n"));
760 if (Version
== IP_VERSION_4
) {
761 Checksum
= NetPseudoHeadChecksum (Src
->Addr
[0], Dst
->Addr
[0], 6, 0);
763 Checksum
= NetIp6PseudoHeadChecksum (&Src
->v6
, &Dst
->v6
, 6, 0);
766 Checksum
= TcpChecksum (Nbuf
, Checksum
);
769 DEBUG ((EFI_D_ERROR
, "TcpInput: received a checksum error packet\n"));
773 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)) {
777 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_FIN
)) {
787 (BOOLEAN
) TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)
790 if ((Tcb
== NULL
) || (Tcb
->State
== TCP_CLOSED
)) {
791 DEBUG ((EFI_D_INFO
, "TcpInput: send reset because no TCB find\n"));
797 Seg
= TcpFormatNetbuf (Tcb
, Nbuf
);
800 // RFC1122 recommended reaction to illegal option
801 // (in fact, an illegal option length) is reset.
803 if (TcpParseOption (Nbuf
->Tcp
, &Option
) == -1) {
806 "TcpInput: reset the peer because of mal-format option for Tcb %p\n",
814 // From now on, the segment is headless
816 NetbufTrim (Nbuf
, (Head
->HeadLen
<< 2), NET_BUF_HEAD
);
820 // Process the segment in LISTEN state.
822 if (Tcb
->State
== TCP_LISTEN
) {
824 // First step: Check RST
826 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
829 "TcpInput: discard a reset segment for TCB %p in listening\n",
837 // Second step: Check ACK.
838 // Any ACK sent to TCP in LISTEN is reseted.
840 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
843 "TcpInput: send reset because of segment with ACK for TCB %p in listening\n",
851 // Third step: Check SYN
853 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
855 // create a child TCB to handle the data
859 Tcb
= TcpCloneTcb (Parent
);
863 "TcpInput: discard a segment because failed to clone a child for TCB%p\n",
872 "TcpInput: create a child for TCB %p in listening\n",
877 // init the TCB structure
879 IP6_COPY_ADDRESS (&Tcb
->LocalEnd
.Ip
, Dst
);
880 IP6_COPY_ADDRESS (&Tcb
->RemoteEnd
.Ip
, Src
);
881 Tcb
->LocalEnd
.Port
= Head
->DstPort
;
882 Tcb
->RemoteEnd
.Port
= Head
->SrcPort
;
884 TcpInitTcbLocal (Tcb
);
885 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
887 TcpSetState (Tcb
, TCP_SYN_RCVD
);
888 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
889 TcpTrimInWnd (Tcb
, Nbuf
);
896 } else if (Tcb
->State
== TCP_SYN_SENT
) {
898 // First step: Check ACK bit
900 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
) && (Seg
->Ack
!= Tcb
->Iss
+ 1)) {
904 "TcpInput: send reset because of wrong ACK received for TCB %p in SYN_SENT\n",
912 // Second step: Check RST bit
914 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
916 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
920 "TcpInput: connection reset by peer for TCB %p in SYN_SENT\n",
924 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
925 goto DROP_CONNECTION
;
930 "TcpInput: discard a reset segment because of no ACK for TCB %p in SYN_SENT\n",
939 // Third step: Check security and precedence. Skipped
943 // Fourth step: Check SYN. Pay attention to sitimulatous open
945 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
947 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
949 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
951 Tcb
->SndUna
= Seg
->Ack
;
954 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
956 if (TCP_SEQ_GT (Tcb
->SndUna
, Tcb
->Iss
)) {
958 TcpSetState (Tcb
, TCP_ESTABLISHED
);
960 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
961 TcpDeliverData (Tcb
);
963 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
964 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)
967 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
968 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
971 TcpTrimInWnd (Tcb
, Nbuf
);
973 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
977 "TcpInput: connection established for TCB %p in SYN_SENT\n",
984 // Received a SYN segment without ACK, simultanous open.
986 TcpSetState (Tcb
, TCP_SYN_RCVD
);
988 ASSERT (Tcb
->SndNxt
== Tcb
->Iss
+ 1);
989 TcpAdjustSndQue (Tcb
, Tcb
->SndNxt
);
991 TcpTrimInWnd (Tcb
, Nbuf
);
995 "TcpInput: simultanous open for TCB %p in SYN_SENT\n",
1007 // Process segment in SYN_RCVD or TCP_CONNECTED states
1011 // Clear probe timer since the RecvWindow is opened.
1013 if (Tcb
->ProbeTimerOn
&& (Seg
->Wnd
!= 0)) {
1014 TcpClearTimer (Tcb
, TCP_TIMER_PROBE
);
1015 Tcb
->ProbeTimerOn
= FALSE
;
1019 // First step: Check whether SEG.SEQ is acceptable
1021 if (TcpSeqAcceptable (Tcb
, Seg
) == 0) {
1024 "TcpInput: sequence acceptance test failed for segment of TCB %p\n",
1028 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
1035 if ((TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
)) &&
1036 (Tcb
->RcvWl2
== Seg
->End
) &&
1037 !TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
| TCP_FLG_FIN
)
1040 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1044 // Second step: Check the RST
1046 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
1048 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset for TCB %p\n", Tcb
));
1050 if (Tcb
->State
== TCP_SYN_RCVD
) {
1052 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_REFUSED
);
1055 // This TCB comes from either a LISTEN TCB,
1056 // or active open TCB with simultanous open.
1057 // Do NOT signal user CONNECTION refused
1058 // if it comes from a LISTEN TCB.
1060 } else if ((Tcb
->State
== TCP_ESTABLISHED
) ||
1061 (Tcb
->State
== TCP_FIN_WAIT_1
) ||
1062 (Tcb
->State
== TCP_FIN_WAIT_2
) ||
1063 (Tcb
->State
== TCP_CLOSE_WAIT
)
1066 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1071 goto DROP_CONNECTION
;
1075 // Trim the data and flags.
1077 TcpTrimInWnd (Tcb
, Nbuf
);
1080 // Third step: Check security and precedence, Ignored
1084 // Fourth step: Check the SYN bit.
1086 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1090 "TcpInput: connection reset because received extra SYN for TCB %p\n",
1094 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1095 goto RESET_THEN_DROP
;
1098 // Fifth step: Check the ACK
1100 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
1103 "TcpInput: segment discard because of no ACK for connected TCB %p\n",
1109 if (Tcb
->IpInfo
->IpVersion
== IP_VERSION_6
&& Tcb
->Tick
== 0) {
1110 Tcp6RefreshNeighbor (Tcb
, Src
, TCP6_KEEP_NEIGHBOR_TIME
* TICKS_PER_SECOND
);
1111 Tcb
->Tick
= TCP6_REFRESH_NEIGHBOR_TICK
;
1115 if (Tcb
->State
== TCP_SYN_RCVD
) {
1117 if (TCP_SEQ_LT (Tcb
->SndUna
, Seg
->Ack
) && TCP_SEQ_LEQ (Seg
->Ack
, Tcb
->SndNxt
)) {
1119 Tcb
->SndWnd
= Seg
->Wnd
;
1120 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1121 Tcb
->SndWl1
= Seg
->Seq
;
1122 Tcb
->SndWl2
= Seg
->Ack
;
1123 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1125 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1126 TcpDeliverData (Tcb
);
1130 "TcpInput: connection established for TCB %p in SYN_RCVD\n",
1135 // Continue the process as ESTABLISHED state
1140 "TcpInput: send reset because of wrong ACK for TCB %p in SYN_RCVD\n",
1148 if (TCP_SEQ_LT (Seg
->Ack
, Tcb
->SndUna
)) {
1152 "TcpInput: ignore the out-of-data ACK for connected TCB %p\n",
1158 } else if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndNxt
)) {
1162 "TcpInput: discard segment for future ACK for connected TCB %p\n",
1171 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1173 if (TCP_FLG_ON (Option
.Flag
, TCP_OPTION_RCVD_TS
)) {
1175 // update TsRecent as specified in page 16 RFC1323.
1176 // RcvWl2 equals to the variable "LastAckSent"
1179 if (TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
) && TCP_SEQ_LT (Tcb
->RcvWl2
, Seg
->End
)) {
1181 Tcb
->TsRecent
= Option
.TSVal
;
1182 Tcb
->TsRecentAge
= mTcpTick
;
1185 TcpComputeRtt (Tcb
, TCP_SUB_TIME (mTcpTick
, Option
.TSEcr
));
1187 } else if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
1189 ASSERT (Tcb
->CongestState
== TCP_CONGEST_OPEN
);
1191 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1192 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1195 if (Seg
->Ack
== Tcb
->SndNxt
) {
1197 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1200 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
1204 // Count duplicate acks.
1206 if ((Seg
->Ack
== Tcb
->SndUna
) &&
1207 (Tcb
->SndUna
!= Tcb
->SndNxt
) &&
1208 (Seg
->Wnd
== Tcb
->SndWnd
) &&
1219 // Congestion avoidance, fast recovery and fast retransmission.
1221 if (((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && (Tcb
->DupAck
< 3)) ||
1222 (Tcb
->CongestState
== TCP_CONGEST_LOSS
)
1225 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1227 if (Tcb
->CWnd
< Tcb
->Ssthresh
) {
1229 Tcb
->CWnd
+= Tcb
->SndMss
;
1232 Tcb
->CWnd
+= MAX (Tcb
->SndMss
* Tcb
->SndMss
/ Tcb
->CWnd
, 1);
1235 Tcb
->CWnd
= MIN (Tcb
->CWnd
, TCP_MAX_WIN
<< Tcb
->SndWndScale
);
1238 if (Tcb
->CongestState
== TCP_CONGEST_LOSS
) {
1239 TcpFastLossRecover (Tcb
, Seg
);
1243 TcpFastRecover (Tcb
, Seg
);
1246 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1248 TcpAdjustSndQue (Tcb
, Seg
->Ack
);
1249 Tcb
->SndUna
= Seg
->Ack
;
1251 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
1252 TCP_SEQ_LT (Tcb
->SndUp
, Seg
->Ack
)
1255 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
1260 // Update window info
1262 if (TCP_SEQ_LT (Tcb
->SndWl1
, Seg
->Seq
) ||
1263 ((Tcb
->SndWl1
== Seg
->Seq
) && TCP_SEQ_LEQ (Tcb
->SndWl2
, Seg
->Ack
))
1266 Right
= Seg
->Ack
+ Seg
->Wnd
;
1268 if (TCP_SEQ_LT (Right
, Tcb
->SndWl2
+ Tcb
->SndWnd
)) {
1270 if ((Tcb
->SndWl1
== Seg
->Seq
) &&
1271 (Tcb
->SndWl2
== Seg
->Ack
) &&
1280 "TcpInput: peer shrinks the window for connected TCB %p\n",
1284 if ((Tcb
->CongestState
== TCP_CONGEST_RECOVER
) && (TCP_SEQ_LT (Right
, Tcb
->Recover
))) {
1286 Tcb
->Recover
= Right
;
1289 if ((Tcb
->CongestState
== TCP_CONGEST_LOSS
) && (TCP_SEQ_LT (Right
, Tcb
->LossRecover
))) {
1291 Tcb
->LossRecover
= Right
;
1294 if (TCP_SEQ_LT (Right
, Tcb
->SndNxt
)) {
1296 Tcb
->SndNxt
= Right
;
1298 if (Right
== Tcb
->SndUna
) {
1300 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1301 TcpSetProbeTimer (Tcb
);
1306 Tcb
->SndWnd
= Seg
->Wnd
;
1307 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1308 Tcb
->SndWl1
= Seg
->Seq
;
1309 Tcb
->SndWl2
= Seg
->Ack
;
1314 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
) && (Tcb
->SndUna
== Tcb
->SndNxt
)) {
1318 "TcpInput: local FIN is ACKed by peer for connected TCB %p\n",
1322 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
);
1326 // Transit the state if proper.
1328 switch (Tcb
->State
) {
1329 case TCP_FIN_WAIT_1
:
1331 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1333 TcpSetState (Tcb
, TCP_FIN_WAIT_2
);
1335 TcpClearAllTimer (Tcb
);
1336 TcpSetTimer (Tcb
, TCP_TIMER_FINWAIT2
, Tcb
->FinWait2Timeout
);
1339 case TCP_FIN_WAIT_2
:
1343 case TCP_CLOSE_WAIT
:
1348 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1350 TcpSetState (Tcb
, TCP_TIME_WAIT
);
1352 TcpClearAllTimer (Tcb
);
1354 if (Tcb
->TimeWaitTimeout
!= 0) {
1356 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1361 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1372 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1374 TcpSetState (Tcb
, TCP_CLOSED
);
1383 if (Tcb
->TimeWaitTimeout
!= 0) {
1385 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1390 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1402 // Sixth step: Check the URG bit.update the Urg point
1403 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1408 TcpSetKeepaliveTimer (Tcb
);
1410 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
) && !TCP_FIN_RCVD (Tcb
->State
)) {
1414 "TcpInput: received urgent data from peer for connected TCB %p\n",
1418 Urg
= Seg
->Seq
+ Seg
->Urg
;
1420 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) && TCP_SEQ_GT (Urg
, Tcb
->RcvUp
)) {
1426 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
);
1430 // Seventh step: Process the segment data
1432 if (Seg
->End
!= Seg
->Seq
) {
1434 if (TCP_FIN_RCVD (Tcb
->State
)) {
1438 "TcpInput: connection reset because data is lost for connected TCB %p\n",
1442 goto RESET_THEN_DROP
;
1445 if (TCP_LOCAL_CLOSED (Tcb
->State
) && (Nbuf
->TotalSize
!= 0)) {
1448 "TcpInput: connection reset because data is lost for connected TCB %p\n",
1452 goto RESET_THEN_DROP
;
1455 TcpQueueData (Tcb
, Nbuf
);
1456 if (TcpDeliverData (Tcb
) == -1) {
1457 goto RESET_THEN_DROP
;
1460 if (!IsListEmpty (&Tcb
->RcvQue
)) {
1461 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1466 // Eighth step: check the FIN.
1467 // This step is moved to TcpDeliverData. FIN will be
1468 // processed in sequence there. Check the comments in
1469 // the beginning of the file header for information.
1473 // Tcb is a new child of the listening Parent,
1476 if (Parent
!= NULL
) {
1477 Tcb
->Parent
= Parent
;
1481 if ((Tcb
->State
!= TCP_CLOSED
) &&
1482 (TcpToSendData (Tcb
, 0) == 0) &&
1483 (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || (Nbuf
->TotalSize
!= 0))
1493 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
, Version
);
1496 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
1505 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
, Version
);
1510 // Tcb is a child of Parent, and it doesn't survive
1512 DEBUG ((EFI_D_WARN
, "TcpInput: Discard a packet\n"));
1515 if ((Parent
!= NULL
) && (Tcb
!= NULL
)) {
1517 ASSERT (Tcb
->Sk
!= NULL
);
1525 Process the received ICMP error messages for TCP.
1527 @param[in] Nbuf The buffer that contains part of the TCP segment without an IP header
1528 truncated from the ICMP error packet.
1529 @param[in] IcmpErr The ICMP error code interpreted from an ICMP error packet.
1530 @param[in] Src Source address of the ICMP error message.
1531 @param[in] Dst Destination address of the ICMP error message.
1532 @param[in] Version IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
1540 IN EFI_IP_ADDRESS
*Src
,
1541 IN EFI_IP_ADDRESS
*Dst
,
1548 EFI_STATUS IcmpErrStatus
;
1549 BOOLEAN IcmpErrIsHard
;
1550 BOOLEAN IcmpErrNotify
;
1552 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
1553 ASSERT (Head
!= NULL
);
1555 Tcb
= TcpLocateTcb (
1563 if (Tcb
== NULL
|| Tcb
->State
== TCP_CLOSED
) {
1569 // Validate the sequence number.
1571 Seq
= NTOHL (Head
->Seq
);
1572 if (!(TCP_SEQ_LEQ (Tcb
->SndUna
, Seq
) && TCP_SEQ_LT (Seq
, Tcb
->SndNxt
))) {
1577 IcmpErrStatus
= IpIoGetIcmpErrStatus (IcmpErr
, Tcb
->Sk
->IpVersion
, &IcmpErrIsHard
, &IcmpErrNotify
);
1579 if (IcmpErrNotify
) {
1581 SOCK_ERROR (Tcb
->Sk
, IcmpErrStatus
);
1584 if (IcmpErrIsHard
) {