]>
git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c
1000538f87446f1ac08482d4500e4b3b7d16112d
2 TCP input process routines.
4 Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php<BR>
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 Check whether the sequence number of the incoming segment is acceptable.
22 @param Tcb Pointer to the TCP_CB of this TCP instance.
23 @param Seg Pointer to the incoming segment.
25 @retval 1 The sequence number is acceptable.
26 @retval 0 The sequence number is not acceptable.
35 return (TCP_SEQ_LEQ (Tcb
->RcvNxt
, Seg
->End
) &&
36 TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
+ Tcb
->RcvWnd
));
41 NewReno fast recovery, RFC3782.
43 @param Tcb Pointer to the TCP_CB of this TCP instance.
44 @param Seg Segment that triggers the fast recovery.
57 // Step 1: Three duplicate ACKs and not in fast recovery
59 if (Tcb
->CongestState
!= TCP_CONGEST_RECOVER
) {
62 // Step 1A: Invoking fast retransmission.
64 FlightSize
= TCP_SUB_SEQ (Tcb
->SndNxt
, Tcb
->SndUna
);
66 Tcb
->Ssthresh
= MAX (FlightSize
>> 1, (UINT32
) (2 * Tcb
->SndMss
));
67 Tcb
->Recover
= Tcb
->SndNxt
;
69 Tcb
->CongestState
= TCP_CONGEST_RECOVER
;
70 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
73 // Step 2: Entering fast retransmission
75 TcpRetransmit (Tcb
, Tcb
->SndUna
);
76 Tcb
->CWnd
= Tcb
->Ssthresh
+ 3 * Tcb
->SndMss
;
78 DEBUG ((EFI_D_NET
, "TcpFastRecover: enter fast retransmission"
79 " for TCB %p, recover point is %d\n", Tcb
, Tcb
->Recover
));
84 // During fast recovery, execute Step 3, 4, 5 of RFC3782
86 if (Seg
->Ack
== Tcb
->SndUna
) {
89 // Step 3: Fast Recovery,
90 // If this is a duplicated ACK, increse Cwnd by SMSS.
93 // Step 4 is skipped here only to be executed later
96 Tcb
->CWnd
+= Tcb
->SndMss
;
97 DEBUG ((EFI_D_NET
, "TcpFastRecover: received another"
98 " duplicated ACK (%d) for TCB %p\n", Seg
->Ack
, Tcb
));
103 // New data is ACKed, check whether it is a
104 // full ACK or partial ACK
106 if (TCP_SEQ_GEQ (Seg
->Ack
, Tcb
->Recover
)) {
109 // Step 5 - Full ACK:
110 // deflate the congestion window, and exit fast recovery
112 FlightSize
= TCP_SUB_SEQ (Tcb
->SndNxt
, Tcb
->SndUna
);
114 Tcb
->CWnd
= MIN (Tcb
->Ssthresh
, FlightSize
+ Tcb
->SndMss
);
116 Tcb
->CongestState
= TCP_CONGEST_OPEN
;
117 DEBUG ((EFI_D_NET
, "TcpFastRecover: received a full ACK(%d)"
118 " for TCB %p, exit fast recovery\n", Seg
->Ack
, Tcb
));
123 // Step 5 - Partial ACK:
124 // fast retransmit the first unacknowledge field
125 // , then deflate the CWnd
127 TcpRetransmit (Tcb
, Seg
->Ack
);
128 Acked
= TCP_SUB_SEQ (Seg
->Ack
, Tcb
->SndUna
);
131 // Deflate the CWnd by the amount of new data
132 // ACKed by SEG.ACK. If more than one SMSS data
133 // is ACKed, add back SMSS byte to CWnd after
135 if (Acked
>= Tcb
->SndMss
) {
136 Acked
-= Tcb
->SndMss
;
142 DEBUG ((EFI_D_NET
, "TcpFastRecover: received a partial"
143 " ACK(%d) for TCB %p\n", Seg
->Ack
, Tcb
));
151 NewReno fast loss recovery, RFC3792.
153 @param Tcb Pointer to the TCP_CB of this TCP instance.
154 @param Seg Segment that triggers the fast loss recovery.
163 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
166 // New data is ACKed, check whether it is a
167 // full ACK or partial ACK
169 if (TCP_SEQ_GEQ (Seg
->Ack
, Tcb
->LossRecover
)) {
172 // Full ACK: exit the loss recovery.
175 Tcb
->CongestState
= TCP_CONGEST_OPEN
;
177 DEBUG ((EFI_D_NET
, "TcpFastLossRecover: received a "
178 "full ACK(%d) for TCB %p\n", Seg
->Ack
, Tcb
));
184 // fast retransmit the first unacknowledge field.
186 TcpRetransmit (Tcb
, Seg
->Ack
);
187 DEBUG ((EFI_D_NET
, "TcpFastLossRecover: received a "
188 "partial ACK(%d) for TCB %p\n", Seg
->Ack
, Tcb
));
195 Compute the RTT as specified in RFC2988.
197 @param Tcb Pointer to the TCP_CB of this TCP instance.
198 @param Measure Currently measured RTT in heart beats.
210 // Step 2.3: Compute the RTO for subsequent RTT measurement.
212 if (Tcb
->SRtt
!= 0) {
214 Var
= Tcb
->SRtt
- (Measure
<< TCP_RTT_SHIFT
);
220 Tcb
->RttVar
= (3 * Tcb
->RttVar
+ Var
) >> 2;
221 Tcb
->SRtt
= 7 * (Tcb
->SRtt
>> 3) + Measure
;
225 // Step 2.2: compute the first RTT measure
227 Tcb
->SRtt
= Measure
<< TCP_RTT_SHIFT
;
228 Tcb
->RttVar
= Measure
<< (TCP_RTT_SHIFT
- 1);
231 Tcb
->Rto
= (Tcb
->SRtt
+ MAX (8, 4 * Tcb
->RttVar
)) >> TCP_RTT_SHIFT
;
234 // Step 2.4: Limit the RTO to at least 1 second
235 // Step 2.5: Limit the RTO to a maxium value that
236 // is at least 60 second
238 if (Tcb
->Rto
< TCP_RTO_MIN
) {
239 Tcb
->Rto
= TCP_RTO_MIN
;
241 } else if (Tcb
->Rto
> TCP_RTO_MAX
) {
242 Tcb
->Rto
= TCP_RTO_MAX
;
246 DEBUG ((EFI_D_NET
, "TcpComputeRtt: new RTT for TCB %p"
247 " computed SRTT: %d RTTVAR: %d RTO: %d\n",
248 Tcb
, Tcb
->SRtt
, Tcb
->RttVar
, Tcb
->Rto
));
254 Trim the data, SYN and FIN to fit into the window defined by Left and Right.
256 @param Nbuf Buffer that contains received TCP segment without IP header.
257 @param Left The sequence number of the window's left edge.
258 @param Right The sequence number of the window's right edge.
272 Seg
= TCPSEG_NETBUF (Nbuf
);
275 // If the segment is completely out of window,
276 // truncate every thing, include SYN and FIN.
278 if (TCP_SEQ_LEQ (Seg
->End
, Left
) || TCP_SEQ_LEQ (Right
, Seg
->Seq
)) {
280 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
281 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
284 NetbufTrim (Nbuf
, Nbuf
->TotalSize
, NET_BUF_HEAD
);
289 // Adjust the buffer header
291 if (TCP_SEQ_LT (Seg
->Seq
, Left
)) {
293 Drop
= TCP_SUB_SEQ (Left
, Seg
->Seq
);
294 Urg
= Seg
->Seq
+ Seg
->Urg
;
297 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
298 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
303 // Adjust the urgent point
305 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
)) {
307 if (TCP_SEQ_LT (Urg
, Seg
->Seq
)) {
309 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_URG
);
311 Seg
->Urg
= (UINT16
) TCP_SUB_SEQ (Urg
, Seg
->Seq
);
316 NetbufTrim (Nbuf
, Drop
, NET_BUF_HEAD
);
321 // Adjust the buffer tail
323 if (TCP_SEQ_GT (Seg
->End
, Right
)) {
325 Drop
= TCP_SUB_SEQ (Seg
->End
, Right
);
328 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
329 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
334 NetbufTrim (Nbuf
, Drop
, NET_BUF_TAIL
);
338 ASSERT (TcpVerifySegment (Nbuf
) != 0);
343 Trim off the data outside the tcb's receive window.
345 @param Tcb Pointer to the TCP_CB of this TCP instance.
346 @param Nbuf Pointer to the NET_BUF containing the received tcp segment.
355 TcpTrimSegment (Nbuf
, Tcb
->RcvNxt
, Tcb
->RcvWl2
+ Tcb
->RcvWnd
);
360 Process the data and FIN flag, check whether to deliver
361 data to the socket layer.
363 @param Tcb Pointer to the TCP_CB of this TCP instance.
365 @retval 0 No error occurred to deliver data.
366 @retval -1 Error condition occurred. Proper response is to reset the
381 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
384 // make sure there is some data queued,
385 // and TCP is in a proper state
387 if (IsListEmpty (&Tcb
->RcvQue
) || !TCP_CONNECTED (Tcb
->State
)) {
393 // Deliver data to the socket layer
395 Entry
= Tcb
->RcvQue
.ForwardLink
;
398 while (Entry
!= &Tcb
->RcvQue
) {
399 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
400 Seg
= TCPSEG_NETBUF (Nbuf
);
402 ASSERT (TcpVerifySegment (Nbuf
) != 0);
403 ASSERT (Nbuf
->Tcp
== NULL
);
405 if (TCP_SEQ_GT (Seg
->Seq
, Seq
)) {
409 Entry
= Entry
->ForwardLink
;
413 RemoveEntryList (&Nbuf
->List
);
416 // RFC793 Eighth step: process FIN in sequence
418 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
421 // The peer sends to us junky data after FIN,
422 // reset the connection.
424 if (!IsListEmpty (&Tcb
->RcvQue
)) {
425 DEBUG ((EFI_D_ERROR
, "TcpDeliverData: data received after"
426 " FIN from peer of TCB %p, reset connection\n", Tcb
));
432 DEBUG ((EFI_D_NET
, "TcpDeliverData: processing FIN "
433 "from peer of TCB %p\n", Tcb
));
435 switch (Tcb
->State
) {
437 case TCP_ESTABLISHED
:
439 TcpSetState (Tcb
, TCP_CLOSE_WAIT
);
444 if (!TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
446 TcpSetState (Tcb
, TCP_CLOSING
);
455 TcpSetState (Tcb
, TCP_TIME_WAIT
);
456 TcpClearAllTimer (Tcb
);
458 if (Tcb
->TimeWaitTimeout
!= 0) {
460 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
463 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
464 "because app disables TIME_WAIT timer for %p\n", Tcb
));
476 // The peer sends to us junk FIN byte. Discard
477 // the buffer then reset the connection
485 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
491 // Don't delay the ack if PUSH flag is on.
493 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_PSH
)) {
495 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
498 if (Nbuf
->TotalSize
!= 0) {
501 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
502 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvUp
)) {
504 if (TCP_SEQ_LEQ (Seg
->End
, Tcb
->RcvUp
)) {
505 Urgent
= Nbuf
->TotalSize
;
507 Urgent
= TCP_SUB_SEQ (Tcb
->RcvUp
, Seg
->Seq
) + 1;
511 SockDataRcvd (Tcb
->Sk
, Nbuf
, Urgent
);
514 if (TCP_FIN_RCVD (Tcb
->State
)) {
516 SockNoMoreData (Tcb
->Sk
);
527 Store the data into the reassemble queue.
529 @param Tcb Pointer to the TCP_CB of this TCP instance.
530 @param Nbuf Pointer to the buffer containing the data to be queued.
545 ASSERT ((Tcb
!= NULL
) && (Nbuf
!= NULL
) && (Nbuf
->Tcp
== NULL
));
549 Seg
= TCPSEG_NETBUF (Nbuf
);
553 // Fast path to process normal case. That is,
554 // no out-of-order segments are received.
556 if (IsListEmpty (Head
)) {
558 InsertTailList (Head
, &Nbuf
->List
);
563 // Find the point to insert the buffer
565 for (Prev
= Head
, Cur
= Head
->ForwardLink
;
567 Prev
= Cur
, Cur
= Cur
->ForwardLink
) {
569 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
571 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
)) {
577 // Check whether the current segment overlaps with the
581 Node
= NET_LIST_USER_STRUCT (Prev
, NET_BUF
, List
);
583 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->End
)) {
585 if (TCP_SEQ_LEQ (Seg
->End
, TCPSEG_NETBUF (Node
)->End
)) {
591 TcpTrimSegment (Nbuf
, TCPSEG_NETBUF (Node
)->End
, Seg
->End
);
595 InsertHeadList (Prev
, &Nbuf
->List
);
597 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
600 // Check the segments after the insert point.
602 while (Cur
!= Head
) {
603 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
605 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->End
, Seg
->End
)) {
607 Cur
= Cur
->ForwardLink
;
609 RemoveEntryList (&Node
->List
);
614 if (TCP_SEQ_LT (TCPSEG_NETBUF (Node
)->Seq
, Seg
->End
)) {
616 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->Seq
, Seg
->Seq
)) {
618 RemoveEntryList (&Nbuf
->List
);
623 TcpTrimSegment (Nbuf
, Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
);
627 Cur
= Cur
->ForwardLink
;
633 Ajust the send queue or the retransmit queue.
635 @param Tcb Pointer to the TCP_CB of this TCP instance.
636 @param Ack The acknowledge seuqence number of the received segment.
651 Cur
= Head
->ForwardLink
;
653 while (Cur
!= Head
) {
654 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
655 Seg
= TCPSEG_NETBUF (Node
);
657 if (TCP_SEQ_GEQ (Seg
->Seq
, Ack
)) {
662 // Remove completely ACKed segments
664 if (TCP_SEQ_LEQ (Seg
->End
, Ack
)) {
665 Cur
= Cur
->ForwardLink
;
667 RemoveEntryList (&Node
->List
);
672 TcpTrimSegment (Node
, Ack
, Seg
->End
);
679 Process the received TCP segments.
681 @param Nbuf Buffer that contains received TCP segment without IP header.
682 @param Src Source address of the segment, or the peer's IP address.
683 @param Dst Destination address of the segment, or the local end's IP
686 @retval 0 Segment is processed successfully. It is either accepted or
687 discarded. But no connection is reset by the segment.
688 @retval -1 A connection is reset by the segment.
707 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
712 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
713 ASSERT (Head
!= NULL
);
715 if (Nbuf
->TotalSize
< sizeof (TCP_HEAD
)) {
716 DEBUG ((EFI_D_NET
, "TcpInput: received a malformed packet\n"));
720 Len
= Nbuf
->TotalSize
- (Head
->HeadLen
<< 2);
722 if ((Head
->HeadLen
< 5) || (Len
< 0) ||
723 (TcpChecksum (Nbuf
, NetPseudoHeadChecksum (Src
, Dst
, 6, 0)) != 0)) {
725 DEBUG ((EFI_D_NET
, "TcpInput: received a malformed packet\n"));
729 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)) {
733 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_FIN
)) {
742 (BOOLEAN
) TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)
745 if ((Tcb
== NULL
) || (Tcb
->State
== TCP_CLOSED
)) {
746 DEBUG ((EFI_D_NET
, "TcpInput: send reset because no TCB found\n"));
752 Seg
= TcpFormatNetbuf (Tcb
, Nbuf
);
755 // RFC1122 recommended reaction to illegal option
756 // (in fact, an illegal option length) is reset.
758 if (TcpParseOption (Nbuf
->Tcp
, &Option
) == -1) {
759 DEBUG ((EFI_D_ERROR
, "TcpInput: reset the peer because"
760 " of malformed option for TCB %p\n", Tcb
));
766 // From now on, the segment is headless
768 NetbufTrim (Nbuf
, (Head
->HeadLen
<< 2), NET_BUF_HEAD
);
772 // Process the segment in LISTEN state.
774 if (Tcb
->State
== TCP_LISTEN
) {
776 // First step: Check RST
778 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
779 DEBUG ((EFI_D_WARN
, "TcpInput: discard a reset segment "
780 "for TCB %p in listening\n", Tcb
));
786 // Second step: Check ACK.
787 // Any ACK sent to TCP in LISTEN is reseted.
789 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
790 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of"
791 " segment with ACK for TCB %p in listening\n", Tcb
));
797 // Third step: Check SYN
799 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
801 // create a child TCB to handle the data
805 Tcb
= TcpCloneTcb (Parent
);
807 DEBUG ((EFI_D_ERROR
, "TcpInput: discard a segment because"
808 " failed to clone a child for TCB %p\n", Tcb
));
813 DEBUG ((EFI_D_NET
, "TcpInput: create a child for TCB %p"
814 " in listening\n", Tcb
));
817 // init the TCB structure
819 Tcb
->LocalEnd
.Ip
= Dst
;
820 Tcb
->LocalEnd
.Port
= Head
->DstPort
;
821 Tcb
->RemoteEnd
.Ip
= Src
;
822 Tcb
->RemoteEnd
.Port
= Head
->SrcPort
;
824 TcpInitTcbLocal (Tcb
);
825 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
827 TcpSetState (Tcb
, TCP_SYN_RCVD
);
828 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
829 TcpTrimInWnd (Tcb
, Nbuf
);
836 } else if (Tcb
->State
== TCP_SYN_SENT
) {
838 // First step: Check ACK bit
840 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
) && (Seg
->Ack
!= Tcb
->Iss
+ 1)) {
842 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of "
843 "wrong ACK received for TCB %p in SYN_SENT\n", Tcb
));
849 // Second step: Check RST bit
851 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
853 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
855 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset by"
856 " peer for TCB %p in SYN_SENT\n", Tcb
));
858 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
859 goto DROP_CONNECTION
;
862 DEBUG ((EFI_D_WARN
, "TcpInput: discard a reset segment "
863 "because of no ACK for TCB %p in SYN_SENT\n", Tcb
));
870 // Third step: Check security and precedence. Skipped
874 // Fourth step: Check SYN. Pay attention to simultaneous open
876 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
878 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
880 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
882 Tcb
->SndUna
= Seg
->Ack
;
885 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
887 if (TCP_SEQ_GT (Tcb
->SndUna
, Tcb
->Iss
)) {
889 TcpSetState (Tcb
, TCP_ESTABLISHED
);
891 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
892 TcpDeliverData (Tcb
);
894 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
895 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
897 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
898 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
901 TcpTrimInWnd (Tcb
, Nbuf
);
903 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
905 DEBUG ((EFI_D_NET
, "TcpInput: connection established"
906 " for TCB %p in SYN_SENT\n", Tcb
));
911 // Received a SYN segment without ACK, simultaneous open.
913 TcpSetState (Tcb
, TCP_SYN_RCVD
);
915 ASSERT (Tcb
->SndNxt
== Tcb
->Iss
+ 1);
916 TcpAdjustSndQue (Tcb
, Tcb
->SndNxt
);
918 TcpTrimInWnd (Tcb
, Nbuf
);
920 DEBUG ((EFI_D_WARN
, "TcpInput: simultaneous open "
921 "for TCB %p in SYN_SENT\n", Tcb
));
931 // Process segment in SYN_RCVD or TCP_CONNECTED states
935 // Clear probe timer since the RecvWindow is opened.
937 if (Tcb
->ProbeTimerOn
&& (Seg
->Wnd
!= 0)) {
938 TcpClearTimer (Tcb
, TCP_TIMER_PROBE
);
939 Tcb
->ProbeTimerOn
= FALSE
;
943 // First step: Check whether SEG.SEQ is acceptable
945 if (TcpSeqAcceptable (Tcb
, Seg
) == 0) {
946 DEBUG ((EFI_D_WARN
, "TcpInput: sequence acceptance"
947 " test failed for segment of TCB %p\n", Tcb
));
949 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
956 if ((TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
)) &&
957 (Tcb
->RcvWl2
== Seg
->End
) &&
958 !TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
| TCP_FLG_FIN
)) {
960 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
964 // Second step: Check the RST
966 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
968 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset for TCB %p\n", Tcb
));
970 if (Tcb
->State
== TCP_SYN_RCVD
) {
972 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_REFUSED
);
975 // This TCB comes from either a LISTEN TCB,
976 // or active open TCB with simultanous open.
977 // Do NOT signal user CONNECTION refused
978 // if it comes from a LISTEN TCB.
980 } else if ((Tcb
->State
== TCP_ESTABLISHED
) ||
981 (Tcb
->State
== TCP_FIN_WAIT_1
) ||
982 (Tcb
->State
== TCP_FIN_WAIT_2
) ||
983 (Tcb
->State
== TCP_CLOSE_WAIT
)) {
985 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
991 goto DROP_CONNECTION
;
995 // Trim the data and flags.
997 TcpTrimInWnd (Tcb
, Nbuf
);
1000 // Third step: Check security and precedence, Ignored
1004 // Fourth step: Check the SYN bit.
1006 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1008 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset "
1009 "because received extra SYN for TCB %p\n", Tcb
));
1011 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1012 goto RESET_THEN_DROP
;
1016 // Fifth step: Check the ACK
1018 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
1019 DEBUG ((EFI_D_WARN
, "TcpInput: segment discard because"
1020 " of no ACK for connected TCB %p\n", Tcb
));
1026 if (Tcb
->State
== TCP_SYN_RCVD
) {
1028 if (TCP_SEQ_LT (Tcb
->SndUna
, Seg
->Ack
) &&
1029 TCP_SEQ_LEQ (Seg
->Ack
, Tcb
->SndNxt
)) {
1031 Tcb
->SndWnd
= Seg
->Wnd
;
1032 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1033 Tcb
->SndWl1
= Seg
->Seq
;
1034 Tcb
->SndWl2
= Seg
->Ack
;
1035 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1037 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1038 TcpDeliverData (Tcb
);
1040 DEBUG ((EFI_D_NET
, "TcpInput: connection established "
1041 " for TCB %p in SYN_RCVD\n", Tcb
));
1044 // Continue the process as ESTABLISHED state
1047 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of"
1048 " wrong ACK for TCB %p in SYN_RCVD\n", Tcb
));
1054 if (TCP_SEQ_LT (Seg
->Ack
, Tcb
->SndUna
)) {
1056 DEBUG ((EFI_D_WARN
, "TcpInput: ignore the out-of-data"
1057 " ACK for connected TCB %p\n", Tcb
));
1061 } else if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndNxt
)) {
1063 DEBUG ((EFI_D_WARN
, "TcpInput: discard segment for "
1064 "future ACK for connected TCB %p\n", Tcb
));
1071 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1073 if (TCP_FLG_ON (Option
.Flag
, TCP_OPTION_RCVD_TS
)) {
1075 // update TsRecent as specified in page 16 RFC1323.
1076 // RcvWl2 equals to the variable "LastAckSent"
1079 if (TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
) &&
1080 TCP_SEQ_LT (Tcb
->RcvWl2
, Seg
->End
)) {
1082 Tcb
->TsRecent
= Option
.TSVal
;
1083 Tcb
->TsRecentAge
= mTcpTick
;
1086 TcpComputeRtt (Tcb
, TCP_SUB_TIME (mTcpTick
, Option
.TSEcr
));
1088 } else if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
1090 ASSERT (Tcb
->CongestState
== TCP_CONGEST_OPEN
);
1092 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1093 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1096 if (Seg
->Ack
== Tcb
->SndNxt
) {
1098 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1101 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
1105 // Count duplicate acks.
1107 if ((Seg
->Ack
== Tcb
->SndUna
) &&
1108 (Tcb
->SndUna
!= Tcb
->SndNxt
) &&
1109 (Seg
->Wnd
== Tcb
->SndWnd
) &&
1119 // Congestion avoidance, fast recovery and fast retransmission.
1121 if (((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && (Tcb
->DupAck
< 3)) ||
1122 (Tcb
->CongestState
== TCP_CONGEST_LOSS
)) {
1124 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1126 if (Tcb
->CWnd
< Tcb
->Ssthresh
) {
1128 Tcb
->CWnd
+= Tcb
->SndMss
;
1131 Tcb
->CWnd
+= MAX (Tcb
->SndMss
* Tcb
->SndMss
/ Tcb
->CWnd
, 1);
1134 Tcb
->CWnd
= MIN (Tcb
->CWnd
, TCP_MAX_WIN
<< Tcb
->SndWndScale
);
1137 if (Tcb
->CongestState
== TCP_CONGEST_LOSS
) {
1138 TcpFastLossRecover (Tcb
, Seg
);
1142 TcpFastRecover (Tcb
, Seg
);
1145 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1147 TcpAdjustSndQue (Tcb
, Seg
->Ack
);
1148 Tcb
->SndUna
= Seg
->Ack
;
1150 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
1151 TCP_SEQ_LT (Tcb
->SndUp
, Seg
->Ack
)) {
1153 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
1158 // Update window info
1160 if (TCP_SEQ_LT (Tcb
->SndWl1
, Seg
->Seq
) ||
1161 ((Tcb
->SndWl1
== Seg
->Seq
) && TCP_SEQ_LEQ (Tcb
->SndWl2
, Seg
->Ack
))) {
1163 Right
= Seg
->Ack
+ Seg
->Wnd
;
1165 if (TCP_SEQ_LT (Right
, Tcb
->SndWl2
+ Tcb
->SndWnd
)) {
1167 if ((Tcb
->SndWl1
== Seg
->Seq
) &&
1168 (Tcb
->SndWl2
== Seg
->Ack
) &&
1174 DEBUG ((EFI_D_WARN
, "TcpInput: peer shrinks the"
1175 " window for connected TCB %p\n", Tcb
));
1177 if ((Tcb
->CongestState
== TCP_CONGEST_RECOVER
) &&
1178 (TCP_SEQ_LT (Right
, Tcb
->Recover
))) {
1180 Tcb
->Recover
= Right
;
1183 if ((Tcb
->CongestState
== TCP_CONGEST_LOSS
) &&
1184 (TCP_SEQ_LT (Right
, Tcb
->LossRecover
))) {
1186 Tcb
->LossRecover
= Right
;
1189 if (TCP_SEQ_LT (Right
, Tcb
->SndNxt
)) {
1191 Tcb
->SndNxt
= Right
;
1193 if (Right
== Tcb
->SndUna
) {
1195 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1196 TcpSetProbeTimer (Tcb
);
1201 Tcb
->SndWnd
= Seg
->Wnd
;
1202 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1203 Tcb
->SndWl1
= Seg
->Seq
;
1204 Tcb
->SndWl2
= Seg
->Ack
;
1209 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
) &&
1210 (Tcb
->SndUna
== Tcb
->SndNxt
)) {
1212 DEBUG ((EFI_D_NET
, "TcpInput: local FIN is ACKed by"
1213 " peer for connected TCB %p\n", Tcb
));
1215 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
);
1219 // Transit the state if proper.
1221 switch (Tcb
->State
) {
1222 case TCP_FIN_WAIT_1
:
1224 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1226 TcpSetState (Tcb
, TCP_FIN_WAIT_2
);
1228 TcpClearAllTimer (Tcb
);
1229 TcpSetTimer (Tcb
, TCP_TIMER_FINWAIT2
, Tcb
->FinWait2Timeout
);
1232 case TCP_FIN_WAIT_2
:
1236 case TCP_CLOSE_WAIT
:
1241 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1243 TcpSetState (Tcb
, TCP_TIME_WAIT
);
1245 TcpClearAllTimer (Tcb
);
1247 if (Tcb
->TimeWaitTimeout
!= 0) {
1249 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1252 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
1253 "because app disables TIME_WAIT timer for %p\n", Tcb
));
1262 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1264 TcpSetState (Tcb
, TCP_CLOSED
);
1273 if (Tcb
->TimeWaitTimeout
!= 0) {
1275 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1278 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
1279 "because app disables TIME_WAIT timer for %p\n", Tcb
));
1290 // Sixth step: Check the URG bit.update the Urg point
1291 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1296 TcpSetKeepaliveTimer (Tcb
);
1298 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
) &&
1299 !TCP_FIN_RCVD (Tcb
->State
))
1302 DEBUG ((EFI_D_NET
, "TcpInput: received urgent data "
1303 "from peer for connected TCB %p\n", Tcb
));
1305 Urg
= Seg
->Seq
+ Seg
->Urg
;
1307 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
1308 TCP_SEQ_GT (Urg
, Tcb
->RcvUp
)) {
1314 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
);
1319 // Seventh step: Process the segment data
1321 if (Seg
->End
!= Seg
->Seq
) {
1323 if (TCP_FIN_RCVD (Tcb
->State
)) {
1325 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset because"
1326 " data is lost for connected TCB %p\n", Tcb
));
1328 goto RESET_THEN_DROP
;
1331 if (TCP_LOCAL_CLOSED (Tcb
->State
) && (Nbuf
->TotalSize
!= 0)) {
1332 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset because"
1333 " data is lost for connected TCB %p\n", Tcb
));
1335 goto RESET_THEN_DROP
;
1338 TcpQueueData (Tcb
, Nbuf
);
1339 if (TcpDeliverData (Tcb
) == -1) {
1340 goto RESET_THEN_DROP
;
1343 if (!IsListEmpty (&Tcb
->RcvQue
)) {
1344 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1349 // Eighth step: check the FIN.
1350 // This step is moved to TcpDeliverData. FIN will be
1351 // processed in sequence there. Check the comments in
1352 // the beginning of the file header for information.
1356 // Tcb is a new child of the listening Parent,
1359 if (Parent
!= NULL
) {
1360 Tcb
->Parent
= Parent
;
1364 if ((Tcb
->State
!= TCP_CLOSED
) &&
1365 (TcpToSendData (Tcb
, 0) == 0) &&
1366 (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || (Nbuf
->TotalSize
!= 0))) {
1375 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1378 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
1387 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1392 // Tcb is a child of Parent, and it doesn't survive
1394 DEBUG ((EFI_D_WARN
, "Tcp4Input: Discard a packet\n"));
1397 if ((Parent
!= NULL
) && (Tcb
!= NULL
)) {
1399 ASSERT (Tcb
->Sk
!= NULL
);
1408 Process the received ICMP error messages for TCP.
1410 @param Nbuf Buffer that contains part of the TCP segment without IP header
1411 truncated from the ICMP error packet.
1412 @param IcmpErr The ICMP error code interpreted from ICMP error packet.
1413 @param Src Source address of the ICMP error message.
1414 @param Dst Destination address of the ICMP error message.
1428 EFI_STATUS IcmpErrStatus
;
1429 BOOLEAN IcmpErrIsHard
;
1430 BOOLEAN IcmpErrNotify
;
1432 if (Nbuf
->TotalSize
< sizeof (TCP_HEAD
)) {
1436 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
1437 ASSERT (Head
!= NULL
);
1438 Tcb
= TcpLocateTcb (
1445 if (Tcb
== NULL
|| Tcb
->State
== TCP_CLOSED
) {
1451 // Validate the sequence number.
1453 Seq
= NTOHL (Head
->Seq
);
1454 if (!(TCP_SEQ_LEQ (Tcb
->SndUna
, Seq
) && TCP_SEQ_LT (Seq
, Tcb
->SndNxt
))) {
1459 IcmpErrStatus
= IpIoGetIcmpErrStatus (
1466 if (IcmpErrNotify
) {
1468 SOCK_ERROR (Tcb
->Sk
, IcmpErrStatus
);
1471 if (IcmpErrIsHard
) {