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.
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
,
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
);
753 if (Nbuf
->TotalSize
< sizeof (TCP_HEAD
)) {
754 DEBUG ((EFI_D_NET
, "TcpInput: received a malformed packet\n"));
758 Len
= Nbuf
->TotalSize
- (Head
->HeadLen
<< 2);
760 if ((Head
->HeadLen
< 5) || (Len
< 0)) {
762 DEBUG ((EFI_D_NET
, "TcpInput: received a malformed packet\n"));
767 if (Version
== IP_VERSION_4
) {
768 Checksum
= NetPseudoHeadChecksum (Src
->Addr
[0], Dst
->Addr
[0], 6, 0);
770 Checksum
= NetIp6PseudoHeadChecksum (&Src
->v6
, &Dst
->v6
, 6, 0);
773 Checksum
= TcpChecksum (Nbuf
, Checksum
);
776 DEBUG ((EFI_D_ERROR
, "TcpInput: received a checksum error packet\n"));
780 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)) {
784 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_FIN
)) {
794 (BOOLEAN
) TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)
797 if ((Tcb
== NULL
) || (Tcb
->State
== TCP_CLOSED
)) {
798 DEBUG ((EFI_D_NET
, "TcpInput: send reset because no TCB found\n"));
804 Seg
= TcpFormatNetbuf (Tcb
, Nbuf
);
807 // RFC1122 recommended reaction to illegal option
808 // (in fact, an illegal option length) is reset.
810 if (TcpParseOption (Nbuf
->Tcp
, &Option
) == -1) {
813 "TcpInput: reset the peer because of malformed option for TCB %p\n",
821 // From now on, the segment is headless
823 NetbufTrim (Nbuf
, (Head
->HeadLen
<< 2), NET_BUF_HEAD
);
827 // Process the segment in LISTEN state.
829 if (Tcb
->State
== TCP_LISTEN
) {
831 // First step: Check RST
833 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
836 "TcpInput: discard a reset segment for TCB %p in listening\n",
844 // Second step: Check ACK.
845 // Any ACK sent to TCP in LISTEN is reseted.
847 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
850 "TcpInput: send reset because of segment with ACK for TCB %p in listening\n",
858 // Third step: Check SYN
860 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
862 // create a child TCB to handle the data
866 Tcb
= TcpCloneTcb (Parent
);
870 "TcpInput: discard a segment because failed to clone a child for TCB %p\n",
879 "TcpInput: create a child for TCB %p in listening\n",
884 // init the TCB structure
886 IP6_COPY_ADDRESS (&Tcb
->LocalEnd
.Ip
, Dst
);
887 IP6_COPY_ADDRESS (&Tcb
->RemoteEnd
.Ip
, Src
);
888 Tcb
->LocalEnd
.Port
= Head
->DstPort
;
889 Tcb
->RemoteEnd
.Port
= Head
->SrcPort
;
891 TcpInitTcbLocal (Tcb
);
892 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
894 TcpSetState (Tcb
, TCP_SYN_RCVD
);
895 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
896 TcpTrimInWnd (Tcb
, Nbuf
);
903 } else if (Tcb
->State
== TCP_SYN_SENT
) {
905 // First step: Check ACK bit
907 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
) && (Seg
->Ack
!= Tcb
->Iss
+ 1)) {
911 "TcpInput: send reset because of wrong ACK received for TCB %p in SYN_SENT\n",
919 // Second step: Check RST bit
921 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
923 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
927 "TcpInput: connection reset by peer for TCB %p in SYN_SENT\n",
931 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
932 goto DROP_CONNECTION
;
937 "TcpInput: discard a reset segment because of no ACK for TCB %p in SYN_SENT\n",
946 // Third step: Check security and precedence. Skipped
950 // Fourth step: Check SYN. Pay attention to simultaneous open
952 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
954 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
956 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
958 Tcb
->SndUna
= Seg
->Ack
;
961 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
963 if (TCP_SEQ_GT (Tcb
->SndUna
, Tcb
->Iss
)) {
965 TcpSetState (Tcb
, TCP_ESTABLISHED
);
967 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
968 TcpDeliverData (Tcb
);
970 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
971 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
))
974 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
975 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
978 TcpTrimInWnd (Tcb
, Nbuf
);
980 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
984 "TcpInput: connection established for TCB %p in SYN_SENT\n",
991 // Received a SYN segment without ACK, simultanous open.
993 TcpSetState (Tcb
, TCP_SYN_RCVD
);
995 ASSERT (Tcb
->SndNxt
== Tcb
->Iss
+ 1);
996 TcpAdjustSndQue (Tcb
, Tcb
->SndNxt
);
998 TcpTrimInWnd (Tcb
, Nbuf
);
1002 "TcpInput: simultaneous open for TCB %p in SYN_SENT\n",
1014 // Process segment in SYN_RCVD or TCP_CONNECTED states
1018 // Clear probe timer since the RecvWindow is opened.
1020 if (Tcb
->ProbeTimerOn
&& (Seg
->Wnd
!= 0)) {
1021 TcpClearTimer (Tcb
, TCP_TIMER_PROBE
);
1022 Tcb
->ProbeTimerOn
= FALSE
;
1026 // First step: Check whether SEG.SEQ is acceptable
1028 if (TcpSeqAcceptable (Tcb
, Seg
) == 0) {
1031 "TcpInput: sequence acceptance test failed for segment of TCB %p\n",
1035 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
1042 if ((TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
)) &&
1043 (Tcb
->RcvWl2
== Seg
->End
) &&
1044 !TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
| TCP_FLG_FIN
))
1047 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1051 // Second step: Check the RST
1053 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
1055 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset for TCB %p\n", Tcb
));
1057 if (Tcb
->State
== TCP_SYN_RCVD
) {
1059 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_REFUSED
);
1062 // This TCB comes from either a LISTEN TCB,
1063 // or active open TCB with simultanous open.
1064 // Do NOT signal user CONNECTION refused
1065 // if it comes from a LISTEN TCB.
1067 } else if ((Tcb
->State
== TCP_ESTABLISHED
) ||
1068 (Tcb
->State
== TCP_FIN_WAIT_1
) ||
1069 (Tcb
->State
== TCP_FIN_WAIT_2
) ||
1070 (Tcb
->State
== TCP_CLOSE_WAIT
))
1073 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1078 goto DROP_CONNECTION
;
1082 // Trim the data and flags.
1084 TcpTrimInWnd (Tcb
, Nbuf
);
1087 // Third step: Check security and precedence, Ignored
1091 // Fourth step: Check the SYN bit.
1093 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1097 "TcpInput: connection reset because received extra SYN for TCB %p\n",
1101 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1102 goto RESET_THEN_DROP
;
1105 // Fifth step: Check the ACK
1107 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
1110 "TcpInput: segment discard because of no ACK for connected TCB %p\n",
1116 if (Tcb
->IpInfo
->IpVersion
== IP_VERSION_6
&& Tcb
->Tick
== 0) {
1117 Tcp6RefreshNeighbor (Tcb
, Src
, TCP6_KEEP_NEIGHBOR_TIME
* TICKS_PER_SECOND
);
1118 Tcb
->Tick
= TCP6_REFRESH_NEIGHBOR_TICK
;
1122 if (Tcb
->State
== TCP_SYN_RCVD
) {
1124 if (TCP_SEQ_LT (Tcb
->SndUna
, Seg
->Ack
) &&
1125 TCP_SEQ_LEQ (Seg
->Ack
, Tcb
->SndNxt
))
1128 Tcb
->SndWnd
= Seg
->Wnd
;
1129 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1130 Tcb
->SndWl1
= Seg
->Seq
;
1131 Tcb
->SndWl2
= Seg
->Ack
;
1132 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1134 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1135 TcpDeliverData (Tcb
);
1139 "TcpInput: connection established for TCB %p in SYN_RCVD\n",
1144 // Continue the process as ESTABLISHED state
1149 "TcpInput: send reset because of wrong ACK for TCB %p in SYN_RCVD\n",
1157 if (TCP_SEQ_LT (Seg
->Ack
, Tcb
->SndUna
)) {
1161 "TcpInput: ignore the out-of-data ACK for connected TCB %p\n",
1167 } else if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndNxt
)) {
1171 "TcpInput: discard segment for future ACK for connected TCB %p\n",
1180 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1182 if (TCP_FLG_ON (Option
.Flag
, TCP_OPTION_RCVD_TS
)) {
1184 // update TsRecent as specified in page 16 RFC1323.
1185 // RcvWl2 equals to the variable "LastAckSent"
1188 if (TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
) &&
1189 TCP_SEQ_LT (Tcb
->RcvWl2
, Seg
->End
))
1192 Tcb
->TsRecent
= Option
.TSVal
;
1193 Tcb
->TsRecentAge
= mTcpTick
;
1196 TcpComputeRtt (Tcb
, TCP_SUB_TIME (mTcpTick
, Option
.TSEcr
));
1198 } else if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
1200 ASSERT (Tcb
->CongestState
== TCP_CONGEST_OPEN
);
1202 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1203 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1206 if (Seg
->Ack
== Tcb
->SndNxt
) {
1208 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1211 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
1215 // Count duplicate acks.
1217 if ((Seg
->Ack
== Tcb
->SndUna
) &&
1218 (Tcb
->SndUna
!= Tcb
->SndNxt
) &&
1219 (Seg
->Wnd
== Tcb
->SndWnd
) &&
1230 // Congestion avoidance, fast recovery and fast retransmission.
1232 if (((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && (Tcb
->DupAck
< 3)) ||
1233 (Tcb
->CongestState
== TCP_CONGEST_LOSS
))
1236 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1238 if (Tcb
->CWnd
< Tcb
->Ssthresh
) {
1240 Tcb
->CWnd
+= Tcb
->SndMss
;
1243 Tcb
->CWnd
+= MAX (Tcb
->SndMss
* Tcb
->SndMss
/ Tcb
->CWnd
, 1);
1246 Tcb
->CWnd
= MIN (Tcb
->CWnd
, TCP_MAX_WIN
<< Tcb
->SndWndScale
);
1249 if (Tcb
->CongestState
== TCP_CONGEST_LOSS
) {
1250 TcpFastLossRecover (Tcb
, Seg
);
1254 TcpFastRecover (Tcb
, Seg
);
1257 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1259 TcpAdjustSndQue (Tcb
, Seg
->Ack
);
1260 Tcb
->SndUna
= Seg
->Ack
;
1262 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
1263 TCP_SEQ_LT (Tcb
->SndUp
, Seg
->Ack
))
1266 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
1271 // Update window info
1273 if (TCP_SEQ_LT (Tcb
->SndWl1
, Seg
->Seq
) ||
1274 ((Tcb
->SndWl1
== Seg
->Seq
) && TCP_SEQ_LEQ (Tcb
->SndWl2
, Seg
->Ack
)))
1277 Right
= Seg
->Ack
+ Seg
->Wnd
;
1279 if (TCP_SEQ_LT (Right
, Tcb
->SndWl2
+ Tcb
->SndWnd
)) {
1281 if ((Tcb
->SndWl1
== Seg
->Seq
) &&
1282 (Tcb
->SndWl2
== Seg
->Ack
) &&
1291 "TcpInput: peer shrinks the window for connected TCB %p\n",
1295 if ((Tcb
->CongestState
== TCP_CONGEST_RECOVER
) &&
1296 (TCP_SEQ_LT (Right
, Tcb
->Recover
)))
1299 Tcb
->Recover
= Right
;
1302 if ((Tcb
->CongestState
== TCP_CONGEST_LOSS
) &&
1303 (TCP_SEQ_LT (Right
, Tcb
->LossRecover
)))
1306 Tcb
->LossRecover
= Right
;
1309 if (TCP_SEQ_LT (Right
, Tcb
->SndNxt
)) {
1311 // Check for Window Retraction in RFC7923 section 2.4.
1312 // The lower n bits of the peer's actual receive window is wiped out if TCP
1313 // window scale is enabled, it will look like the peer is shrinking the window.
1314 // Check whether the SndNxt is out of the advertised receive window by more than
1315 // 2^Rcv.Wind.Shift before moving the SndNxt to the left.
1319 "TcpInput: peer advise negative useable window for connected TCB %p\n",
1322 Usable
= TCP_SUB_SEQ (Tcb
->SndNxt
, Right
);
1323 if ((Usable
>> Tcb
->SndWndScale
) > 0) {
1326 "TcpInput: SndNxt is out of window by more than window scale for TCB %p\n",
1329 Tcb
->SndNxt
= Right
;
1331 if (Right
== Tcb
->SndUna
) {
1333 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1334 TcpSetProbeTimer (Tcb
);
1339 Tcb
->SndWnd
= Seg
->Wnd
;
1340 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1341 Tcb
->SndWl1
= Seg
->Seq
;
1342 Tcb
->SndWl2
= Seg
->Ack
;
1347 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
) &&
1348 (Tcb
->SndUna
== Tcb
->SndNxt
))
1353 "TcpInput: local FIN is ACKed by peer for connected TCB %p\n",
1357 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
);
1361 // Transit the state if proper.
1363 switch (Tcb
->State
) {
1364 case TCP_FIN_WAIT_1
:
1366 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1368 TcpSetState (Tcb
, TCP_FIN_WAIT_2
);
1370 TcpClearAllTimer (Tcb
);
1371 TcpSetTimer (Tcb
, TCP_TIMER_FINWAIT2
, Tcb
->FinWait2Timeout
);
1374 case TCP_FIN_WAIT_2
:
1378 case TCP_CLOSE_WAIT
:
1383 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1385 TcpSetState (Tcb
, TCP_TIME_WAIT
);
1387 TcpClearAllTimer (Tcb
);
1389 if (Tcb
->TimeWaitTimeout
!= 0) {
1391 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1396 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1407 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1409 TcpSetState (Tcb
, TCP_CLOSED
);
1418 if (Tcb
->TimeWaitTimeout
!= 0) {
1420 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1425 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1437 // Sixth step: Check the URG bit.update the Urg point
1438 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1443 TcpSetKeepaliveTimer (Tcb
);
1445 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
) && !TCP_FIN_RCVD (Tcb
->State
)) {
1449 "TcpInput: received urgent data from peer for connected TCB %p\n",
1453 Urg
= Seg
->Seq
+ Seg
->Urg
;
1455 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
1456 TCP_SEQ_GT (Urg
, Tcb
->RcvUp
))
1463 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
);
1467 // Seventh step: Process the segment data
1469 if (Seg
->End
!= Seg
->Seq
) {
1471 if (TCP_FIN_RCVD (Tcb
->State
)) {
1475 "TcpInput: connection reset because data is lost for connected TCB %p\n",
1479 goto RESET_THEN_DROP
;
1482 if (TCP_LOCAL_CLOSED (Tcb
->State
) && (Nbuf
->TotalSize
!= 0)) {
1485 "TcpInput: connection reset because data is lost for connected TCB %p\n",
1489 goto RESET_THEN_DROP
;
1492 TcpQueueData (Tcb
, Nbuf
);
1493 if (TcpDeliverData (Tcb
) == -1) {
1494 goto RESET_THEN_DROP
;
1497 if (!IsListEmpty (&Tcb
->RcvQue
)) {
1498 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1503 // Eighth step: check the FIN.
1504 // This step is moved to TcpDeliverData. FIN will be
1505 // processed in sequence there. Check the comments in
1506 // the beginning of the file header for information.
1510 // Tcb is a new child of the listening Parent,
1513 if (Parent
!= NULL
) {
1514 Tcb
->Parent
= Parent
;
1518 if ((Tcb
->State
!= TCP_CLOSED
) &&
1519 (TcpToSendData (Tcb
, 0) == 0) &&
1520 (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || (Nbuf
->TotalSize
!= 0)))
1530 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
, Version
);
1533 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
1542 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
, Version
);
1547 // Tcb is a child of Parent, and it doesn't survive
1549 DEBUG ((EFI_D_WARN
, "TcpInput: Discard a packet\n"));
1552 if ((Parent
!= NULL
) && (Tcb
!= NULL
)) {
1554 ASSERT (Tcb
->Sk
!= NULL
);
1562 Process the received ICMP error messages for TCP.
1564 @param[in] Nbuf The buffer that contains part of the TCP segment without an IP header
1565 truncated from the ICMP error packet.
1566 @param[in] IcmpErr The ICMP error code interpreted from an ICMP error packet.
1567 @param[in] Src Source address of the ICMP error message.
1568 @param[in] Dst Destination address of the ICMP error message.
1569 @param[in] Version IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
1577 IN EFI_IP_ADDRESS
*Src
,
1578 IN EFI_IP_ADDRESS
*Dst
,
1585 EFI_STATUS IcmpErrStatus
;
1586 BOOLEAN IcmpErrIsHard
;
1587 BOOLEAN IcmpErrNotify
;
1589 if (Nbuf
->TotalSize
< sizeof (TCP_HEAD
)) {
1593 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
1594 ASSERT (Head
!= NULL
);
1596 Tcb
= TcpLocateTcb (
1604 if (Tcb
== NULL
|| Tcb
->State
== TCP_CLOSED
) {
1610 // Validate the sequence number.
1612 Seq
= NTOHL (Head
->Seq
);
1613 if (!(TCP_SEQ_LEQ (Tcb
->SndUna
, Seq
) && TCP_SEQ_LT (Seq
, Tcb
->SndNxt
))) {
1618 IcmpErrStatus
= IpIoGetIcmpErrStatus (
1625 if (IcmpErrNotify
) {
1627 SOCK_ERROR (Tcb
->Sk
, IcmpErrStatus
);
1630 if (IcmpErrIsHard
) {