]>
git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c
f5ca9ac5484f39f996055502e3dd5f573eb4295e
2 TCP input process routines.
4 Copyright (c) 2005 - 2007, Intel Corporation<BR>
5 All rights reserved. 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
->RcvWl2
, Seg
->End
) &&
36 TCP_SEQ_LEQ (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_INFO
, "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_INFO
, "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_INFO
, "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_INFO
, "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_INFO
, "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_INFO
, "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_INFO
, "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.
260 @return 0 The data is successfully trimmed.
274 Seg
= TCPSEG_NETBUF (Nbuf
);
277 // If the segment is completely out of window,
278 // truncate every thing, include SYN and FIN.
280 if (TCP_SEQ_LEQ (Seg
->End
, Left
) || TCP_SEQ_LEQ (Right
, Seg
->Seq
)) {
282 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
283 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
286 NetbufTrim (Nbuf
, Nbuf
->TotalSize
, NET_BUF_HEAD
);
291 // Adjust the buffer header
293 if (TCP_SEQ_LT (Seg
->Seq
, Left
)) {
295 Drop
= TCP_SUB_SEQ (Left
, Seg
->Seq
);
296 Urg
= Seg
->Seq
+ Seg
->Urg
;
299 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
300 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
305 // Adjust the urgent point
307 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
)) {
309 if (TCP_SEQ_LT (Urg
, Seg
->Seq
)) {
311 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_URG
);
313 Seg
->Urg
= (UINT16
) TCP_SUB_SEQ (Urg
, Seg
->Seq
);
318 NetbufTrim (Nbuf
, Drop
, NET_BUF_HEAD
);
323 // Adjust the buffer tail
325 if (TCP_SEQ_GT (Seg
->End
, Right
)) {
327 Drop
= TCP_SUB_SEQ (Seg
->End
, Right
);
330 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
331 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
336 NetbufTrim (Nbuf
, Drop
, NET_BUF_TAIL
);
340 ASSERT (TcpVerifySegment (Nbuf
) != 0);
346 Trim off the data outside the tcb's receive window.
348 @param Tcb Pointer to the TCP_CB of this TCP instance.
349 @param Nbuf Pointer to the NET_BUF containing the received tcp segment.
351 @return 0 The data is trimmed.
360 return TcpTrimSegment (Nbuf
, Tcb
->RcvNxt
, Tcb
->RcvWl2
+ Tcb
->RcvWnd
);
365 Process the data and FIN flag, check whether to deliver
366 data to the socket layer.
368 @param Tcb Pointer to the TCP_CB of this TCP instance.
370 @retval 0 No error occurred to deliver data.
371 @retval -1 Error condition occurred. Proper response is to reset the
386 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
389 // make sure there is some data queued,
390 // and TCP is in a proper state
392 if (IsListEmpty (&Tcb
->RcvQue
) || !TCP_CONNECTED (Tcb
->State
)) {
398 // Deliver data to the socket layer
400 Entry
= Tcb
->RcvQue
.ForwardLink
;
403 while (Entry
!= &Tcb
->RcvQue
) {
404 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
405 Seg
= TCPSEG_NETBUF (Nbuf
);
407 ASSERT (TcpVerifySegment (Nbuf
) != 0);
408 ASSERT (Nbuf
->Tcp
== NULL
);
410 if (TCP_SEQ_GT (Seg
->Seq
, Seq
)) {
414 Entry
= Entry
->ForwardLink
;
418 RemoveEntryList (&Nbuf
->List
);
421 // RFC793 Eighth step: process FIN in sequence
423 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
426 // The peer sends to us junky data after FIN,
427 // reset the connection.
429 if (!IsListEmpty (&Tcb
->RcvQue
)) {
430 DEBUG ((EFI_D_ERROR
, "TcpDeliverData: data received after"
431 " FIN from peer of TCB %p, reset connection\n", Tcb
));
437 DEBUG ((EFI_D_INFO
, "TcpDeliverData: processing FIN "
438 "from peer of TCB %p\n", Tcb
));
440 switch (Tcb
->State
) {
442 case TCP_ESTABLISHED
:
444 TcpSetState (Tcb
, TCP_CLOSE_WAIT
);
449 if (!TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
451 TcpSetState (Tcb
, TCP_CLOSING
);
460 TcpSetState (Tcb
, TCP_TIME_WAIT
);
461 TcpClearAllTimer (Tcb
);
463 if (Tcb
->TimeWaitTimeout
!= 0) {
465 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
468 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
469 "because app disables TIME_WAIT timer for %p\n", Tcb
));
481 // The peer sends to us junk FIN byte. Discard
482 // the buffer then reset the connection
491 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
497 // Don't delay the ack if PUSH flag is on.
499 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_PSH
)) {
501 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
504 if (Nbuf
->TotalSize
) {
507 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
508 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvUp
)) {
510 if (TCP_SEQ_LEQ (Seg
->End
, Tcb
->RcvUp
)) {
511 Urgent
= Nbuf
->TotalSize
;
513 Urgent
= TCP_SUB_SEQ (Tcb
->RcvUp
, Seg
->Seq
) + 1;
517 SockDataRcvd (Tcb
->Sk
, Nbuf
, Urgent
);
520 if (TCP_FIN_RCVD (Tcb
->State
)) {
522 SockNoMoreData (Tcb
->Sk
);
533 Store the data into the reassemble queue.
535 @param Tcb Pointer to the TCP_CB of this TCP instance.
536 @param Nbuf Pointer to the buffer containing the data to be queued.
551 ASSERT ((Tcb
!= NULL
) && (Nbuf
!= NULL
) && (Nbuf
->Tcp
== NULL
));
555 Seg
= TCPSEG_NETBUF (Nbuf
);
559 // Fast path to process normal case. That is,
560 // no out-of-order segments are received.
562 if (IsListEmpty (Head
)) {
564 InsertTailList (Head
, &Nbuf
->List
);
569 // Find the point to insert the buffer
571 for (Prev
= Head
, Cur
= Head
->ForwardLink
;
573 Prev
= Cur
, Cur
= Cur
->ForwardLink
) {
575 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
577 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
)) {
583 // Check whether the current segment overlaps with the
587 Node
= NET_LIST_USER_STRUCT (Prev
, NET_BUF
, List
);
589 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->End
)) {
591 if (TCP_SEQ_LEQ (Seg
->End
, TCPSEG_NETBUF (Node
)->End
)) {
597 TcpTrimSegment (Nbuf
, TCPSEG_NETBUF (Node
)->End
, Seg
->End
);
601 InsertHeadList (Prev
, &Nbuf
->List
);
603 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
606 // Check the segments after the insert point.
608 while (Cur
!= Head
) {
609 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
611 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->End
, Seg
->End
)) {
613 Cur
= Cur
->ForwardLink
;
615 RemoveEntryList (&Node
->List
);
620 if (TCP_SEQ_LT (TCPSEG_NETBUF (Node
)->Seq
, Seg
->End
)) {
622 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->Seq
, Seg
->Seq
)) {
624 RemoveEntryList (&Nbuf
->List
);
629 TcpTrimSegment (Nbuf
, Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
);
633 Cur
= Cur
->ForwardLink
;
639 Ajust the send queue or the retransmit queue.
641 @param Tcb Pointer to the TCP_CB of this TCP instance.
642 @param Ack The acknowledge seuqence number of the received segment.
657 Cur
= Head
->ForwardLink
;
659 while (Cur
!= Head
) {
660 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
661 Seg
= TCPSEG_NETBUF (Node
);
663 if (TCP_SEQ_GEQ (Seg
->Seq
, Ack
)) {
668 // Remove completely ACKed segments
670 if (TCP_SEQ_LEQ (Seg
->End
, Ack
)) {
671 Cur
= Cur
->ForwardLink
;
673 RemoveEntryList (&Node
->List
);
678 TcpTrimSegment (Node
, Ack
, Seg
->End
);
685 Process the received TCP segments.
687 @param Nbuf Buffer that contains received TCP segment without IP header.
688 @param Src Source address of the segment, or the peer's IP address.
689 @param Dst Destination address of the segment, or the local end's IP
692 @retval 0 Segment is processed successfully. It is either accepted or
693 discarded. But no connection is reset by the segment.
694 @retval -1 A connection is reset by the segment.
713 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
718 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
719 Len
= Nbuf
->TotalSize
- (Head
->HeadLen
<< 2);
721 if ((Head
->HeadLen
< 5) || (Len
< 0) ||
722 (TcpChecksum (Nbuf
, NetPseudoHeadChecksum (Src
, Dst
, 6, 0)) != 0)) {
724 DEBUG ((EFI_D_INFO
, "TcpInput: received an mal-formated packet\n"));
728 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)) {
732 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_FIN
)) {
741 (BOOLEAN
) TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)
744 if ((Tcb
== NULL
) || (Tcb
->State
== TCP_CLOSED
)) {
745 DEBUG ((EFI_D_INFO
, "TcpInput: send reset because no TCB find\n"));
751 Seg
= TcpFormatNetbuf (Tcb
, Nbuf
);
754 // RFC1122 recommended reaction to illegal option
755 // (in fact, an illegal option length) is reset.
757 if (TcpParseOption (Nbuf
->Tcp
, &Option
) == -1) {
758 DEBUG ((EFI_D_ERROR
, "TcpInput: reset the peer because"
759 " of mal-format option for Tcb %p\n", Tcb
));
765 // From now on, the segment is headless
767 NetbufTrim (Nbuf
, (Head
->HeadLen
<< 2), NET_BUF_HEAD
);
771 // Process the segment in LISTEN state.
773 if (Tcb
->State
== TCP_LISTEN
) {
775 // First step: Check RST
777 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
778 DEBUG ((EFI_D_WARN
, "TcpInput: discard a reset segment "
779 "for TCB %p in listening\n", Tcb
));
785 // Second step: Check ACK.
786 // Any ACK sent to TCP in LISTEN is reseted.
788 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
789 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of"
790 " segment with ACK for TCB %p in listening\n", Tcb
));
796 // Third step: Check SYN
798 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
800 // create a child TCB to handle the data
804 Tcb
= TcpCloneTcb (Parent
);
806 DEBUG ((EFI_D_ERROR
, "TcpInput: discard a segment because"
807 "failed to clone a child for TCB%x\n", Tcb
));
812 DEBUG ((EFI_D_INFO
, "TcpInput: create a child for TCB %p"
813 " in listening\n", Tcb
));
816 // init the TCB structure
818 Tcb
->LocalEnd
.Ip
= Dst
;
819 Tcb
->LocalEnd
.Port
= Head
->DstPort
;
820 Tcb
->RemoteEnd
.Ip
= Src
;
821 Tcb
->RemoteEnd
.Port
= Head
->SrcPort
;
823 TcpInitTcbLocal (Tcb
);
824 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
826 TcpSetState (Tcb
, TCP_SYN_RCVD
);
827 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
828 TcpTrimInWnd (Tcb
, Nbuf
);
835 } else if (Tcb
->State
== TCP_SYN_SENT
) {
837 // First step: Check ACK bit
839 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
) && (Seg
->Ack
!= Tcb
->Iss
+ 1)) {
841 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of "
842 "wrong ACK received for TCB %p in SYN_SENT\n", Tcb
));
848 // Second step: Check RST bit
850 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
852 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
854 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset by"
855 " peer for TCB %p in SYN_SENT\n", Tcb
));
857 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
858 goto DROP_CONNECTION
;
861 DEBUG ((EFI_D_WARN
, "TcpInput: discard a reset segment "
862 "because of no ACK for TCB %p in SYN_SENT\n", Tcb
));
869 // Third step: Check security and precedence. Skipped
873 // Fourth step: Check SYN. Pay attention to sitimulatous open
875 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
877 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
879 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
881 Tcb
->SndUna
= Seg
->Ack
;
884 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
886 if (TCP_SEQ_GT (Tcb
->SndUna
, Tcb
->Iss
)) {
888 TcpSetState (Tcb
, TCP_ESTABLISHED
);
890 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
891 TcpDeliverData (Tcb
);
893 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
894 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
896 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
897 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
900 TcpTrimInWnd (Tcb
, Nbuf
);
902 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
904 DEBUG ((EFI_D_INFO
, "TcpInput: connection established"
905 " for TCB %p in SYN_SENT\n", Tcb
));
910 // Received a SYN segment without ACK, simultanous open.
912 TcpSetState (Tcb
, TCP_SYN_RCVD
);
914 ASSERT (Tcb
->SndNxt
== Tcb
->Iss
+ 1);
915 TcpAdjustSndQue (Tcb
, Tcb
->SndNxt
);
917 TcpTrimInWnd (Tcb
, Nbuf
);
919 DEBUG ((EFI_D_WARN
, "TcpInput: simultanous open "
920 "for TCB %p in SYN_SENT\n", Tcb
));
930 // Process segment in SYN_RCVD or TCP_CONNECTED states
934 // First step: Check whether SEG.SEQ is acceptable
936 if (TcpSeqAcceptable (Tcb
, Seg
) == 0) {
937 DEBUG ((EFI_D_WARN
, "TcpInput: sequence acceptance"
938 " test failed for segment of TCB %p\n", Tcb
));
940 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
947 if ((TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
)) &&
948 (Tcb
->RcvWl2
== Seg
->End
) &&
949 !TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
| TCP_FLG_FIN
)) {
951 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
955 // Second step: Check the RST
957 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
959 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset for TCB %p\n", Tcb
));
961 if (Tcb
->State
== TCP_SYN_RCVD
) {
963 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_REFUSED
);
966 // This TCB comes from either a LISTEN TCB,
967 // or active open TCB with simultanous open.
968 // Do NOT signal user CONNECTION refused
969 // if it comes from a LISTEN TCB.
971 } else if ((Tcb
->State
== TCP_ESTABLISHED
) ||
972 (Tcb
->State
== TCP_FIN_WAIT_1
) ||
973 (Tcb
->State
== TCP_FIN_WAIT_2
) ||
974 (Tcb
->State
== TCP_CLOSE_WAIT
)) {
976 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
982 goto DROP_CONNECTION
;
986 // Trim the data and flags.
988 TcpTrimInWnd (Tcb
, Nbuf
);
991 // Third step: Check security and precedence, Ignored
995 // Fourth step: Check the SYN bit.
997 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
999 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset "
1000 "because received extra SYN for TCB %p\n", Tcb
));
1002 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1003 goto RESET_THEN_DROP
;
1007 // Fifth step: Check the ACK
1009 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
1010 DEBUG ((EFI_D_WARN
, "TcpInput: segment discard because"
1011 " of no ACK for connected TCB %p\n", Tcb
));
1017 if (Tcb
->State
== TCP_SYN_RCVD
) {
1019 if (TCP_SEQ_LT (Tcb
->SndUna
, Seg
->Ack
) &&
1020 TCP_SEQ_LEQ (Seg
->Ack
, Tcb
->SndNxt
)) {
1022 Tcb
->SndWnd
= Seg
->Wnd
;
1023 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1024 Tcb
->SndWl1
= Seg
->Seq
;
1025 Tcb
->SndWl2
= Seg
->Ack
;
1026 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1028 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1029 TcpDeliverData (Tcb
);
1031 DEBUG ((EFI_D_INFO
, "TcpInput: connection established "
1032 " for TCB %p in SYN_RCVD\n", Tcb
));
1035 // Continue the process as ESTABLISHED state
1038 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of"
1039 " wrong ACK for TCB %p in SYN_RCVD\n", Tcb
));
1045 if (TCP_SEQ_LT (Seg
->Ack
, Tcb
->SndUna
)) {
1047 DEBUG ((EFI_D_WARN
, "TcpInput: ignore the out-of-data"
1048 " ACK for connected TCB %p\n", Tcb
));
1052 } else if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndNxt
)) {
1054 DEBUG ((EFI_D_WARN
, "TcpInput: discard segment for "
1055 "future ACK for connected TCB %p\n", Tcb
));
1062 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1064 if (TCP_FLG_ON (Option
.Flag
, TCP_OPTION_RCVD_TS
)) {
1066 // update TsRecent as specified in page 16 RFC1323.
1067 // RcvWl2 equals to the variable "LastAckSent"
1070 if (TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
) &&
1071 TCP_SEQ_LT (Tcb
->RcvWl2
, Seg
->End
)) {
1073 Tcb
->TsRecent
= Option
.TSVal
;
1074 Tcb
->TsRecentAge
= mTcpTick
;
1077 TcpComputeRtt (Tcb
, TCP_SUB_TIME (mTcpTick
, Option
.TSEcr
));
1079 } else if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
1081 ASSERT (Tcb
->CongestState
== TCP_CONGEST_OPEN
);
1083 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1084 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1087 if (Seg
->Ack
== Tcb
->SndNxt
) {
1089 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1092 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
1096 // Count duplicate acks.
1098 if ((Seg
->Ack
== Tcb
->SndUna
) &&
1099 (Tcb
->SndUna
!= Tcb
->SndNxt
) &&
1100 (Seg
->Wnd
== Tcb
->SndWnd
) &&
1110 // Congestion avoidance, fast recovery and fast retransmission.
1112 if (((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && (Tcb
->DupAck
< 3)) ||
1113 (Tcb
->CongestState
== TCP_CONGEST_LOSS
)) {
1115 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1117 if (Tcb
->CWnd
< Tcb
->Ssthresh
) {
1119 Tcb
->CWnd
+= Tcb
->SndMss
;
1122 Tcb
->CWnd
+= MAX (Tcb
->SndMss
* Tcb
->SndMss
/ Tcb
->CWnd
, 1);
1125 Tcb
->CWnd
= MIN (Tcb
->CWnd
, TCP_MAX_WIN
<< Tcb
->SndWndScale
);
1128 if (Tcb
->CongestState
== TCP_CONGEST_LOSS
) {
1129 TcpFastLossRecover (Tcb
, Seg
);
1133 TcpFastRecover (Tcb
, Seg
);
1136 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1138 TcpAdjustSndQue (Tcb
, Seg
->Ack
);
1139 Tcb
->SndUna
= Seg
->Ack
;
1141 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
1142 TCP_SEQ_LT (Tcb
->SndUp
, Seg
->Ack
)) {
1144 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
1149 // Update window info
1151 if (TCP_SEQ_LT (Tcb
->SndWl1
, Seg
->Seq
) ||
1152 ((Tcb
->SndWl1
== Seg
->Seq
) && TCP_SEQ_LEQ (Tcb
->SndWl2
, Seg
->Ack
))) {
1154 Right
= Seg
->Ack
+ Seg
->Wnd
;
1156 if (TCP_SEQ_LT (Right
, Tcb
->SndWl2
+ Tcb
->SndWnd
)) {
1158 if ((Tcb
->SndWl1
== Seg
->Seq
) &&
1159 (Tcb
->SndWl2
== Seg
->Ack
) &&
1165 DEBUG ((EFI_D_WARN
, "TcpInput: peer shrinks the"
1166 " window for connected TCB %p\n", Tcb
));
1168 if ((Tcb
->CongestState
== TCP_CONGEST_RECOVER
) &&
1169 (TCP_SEQ_LT (Right
, Tcb
->Recover
))) {
1171 Tcb
->Recover
= Right
;
1174 if ((Tcb
->CongestState
== TCP_CONGEST_LOSS
) &&
1175 (TCP_SEQ_LT (Right
, Tcb
->LossRecover
))) {
1177 Tcb
->LossRecover
= Right
;
1180 if (TCP_SEQ_LT (Right
, Tcb
->SndNxt
)) {
1182 Tcb
->SndNxt
= Right
;
1184 if (Right
== Tcb
->SndUna
) {
1186 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1187 TcpSetProbeTimer (Tcb
);
1192 Tcb
->SndWnd
= Seg
->Wnd
;
1193 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1194 Tcb
->SndWl1
= Seg
->Seq
;
1195 Tcb
->SndWl2
= Seg
->Ack
;
1200 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
) &&
1201 (Tcb
->SndUna
== Tcb
->SndNxt
)) {
1203 DEBUG ((EFI_D_INFO
, "TcpInput: local FIN is ACKed by"
1204 " peer for connected TCB %p\n", Tcb
));
1206 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
);
1210 // Transit the state if proper.
1212 switch (Tcb
->State
) {
1213 case TCP_FIN_WAIT_1
:
1215 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1217 TcpSetState (Tcb
, TCP_FIN_WAIT_2
);
1219 TcpClearAllTimer (Tcb
);
1220 TcpSetTimer (Tcb
, TCP_TIMER_FINWAIT2
, Tcb
->FinWait2Timeout
);
1223 case TCP_FIN_WAIT_2
:
1227 case TCP_CLOSE_WAIT
:
1232 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1234 TcpSetState (Tcb
, TCP_TIME_WAIT
);
1236 TcpClearAllTimer (Tcb
);
1238 if (Tcb
->TimeWaitTimeout
!= 0) {
1240 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1243 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
1244 "because app disables TIME_WAIT timer for %p\n", Tcb
));
1253 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1255 TcpSetState (Tcb
, TCP_CLOSED
);
1264 if (Tcb
->TimeWaitTimeout
!= 0) {
1266 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1269 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
1270 "because app disables TIME_WAIT timer for %p\n", Tcb
));
1278 // Sixth step: Check the URG bit.update the Urg point
1279 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1284 TcpSetKeepaliveTimer (Tcb
);
1286 if (TCP_TIMER_ON (Tcb
->EnabledTimer
, TCP_TIMER_PROBE
)) {
1288 TcpClearTimer (Tcb
, TCP_TIMER_PROBE
);
1291 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
) &&
1292 !TCP_FIN_RCVD (Tcb
->State
)) {
1294 DEBUG ((EFI_D_INFO
, "TcpInput: received urgent data "
1295 "from peer for connected TCB %p\n", Tcb
));
1297 Urg
= Seg
->Seq
+ Seg
->Urg
;
1299 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
1300 TCP_SEQ_GT (Urg
, Tcb
->RcvUp
)) {
1306 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
);
1311 // Seventh step: Process the segment data
1313 if (Seg
->End
!= Seg
->Seq
) {
1315 if (TCP_FIN_RCVD (Tcb
->State
)) {
1317 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset because"
1318 " data is lost for connected TCB %p\n", Tcb
));
1320 goto RESET_THEN_DROP
;
1323 if (TCP_LOCAL_CLOSED (Tcb
->State
) && (Nbuf
->TotalSize
!= 0)) {
1324 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset because"
1325 " data is lost for connected TCB %p\n", Tcb
));
1327 goto RESET_THEN_DROP
;
1330 TcpQueueData (Tcb
, Nbuf
);
1331 if (TcpDeliverData (Tcb
) == -1) {
1332 goto RESET_THEN_DROP
;
1335 if (!IsListEmpty (&Tcb
->RcvQue
)) {
1336 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1341 // Eighth step: check the FIN.
1342 // This step is moved to TcpDeliverData. FIN will be
1343 // processed in sequence there. Check the comments in
1344 // the beginning of the file header for information.
1348 // Tcb is a new child of the listening Parent,
1351 if (Parent
!= NULL
) {
1352 Tcb
->Parent
= Parent
;
1356 if ((Tcb
->State
!= TCP_CLOSED
) &&
1357 (TcpToSendData (Tcb
, 0) == 0) &&
1358 (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || Nbuf
->TotalSize
)) {
1367 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1370 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
1379 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1384 // Tcb is a child of Parent, and it doesn't survive
1386 DEBUG ((EFI_D_WARN
, "Tcp4Input: Discard a packet\n"));
1389 if ((Parent
!= NULL
) && (Tcb
!= NULL
)) {
1391 ASSERT (Tcb
->Sk
!= NULL
);
1400 Process the received ICMP error messages for TCP.
1402 @param Nbuf Buffer that contains part of the TCP segment without IP header
1403 truncated from the ICMP error packet.
1404 @param IcmpErr The ICMP error code interpreted from ICMP error packet.
1405 @param Src Source address of the ICMP error message.
1406 @param Dst Destination address of the ICMP error message.
1412 IN ICMP_ERROR IcmpErr
,
1420 EFI_STATUS IcmpErrStatus
;
1421 BOOLEAN IcmpErrIsHard
;
1422 BOOLEAN IcmpErrNotify
;
1424 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
1425 Tcb
= TcpLocateTcb (
1432 if (Tcb
== NULL
|| Tcb
->State
== TCP_CLOSED
) {
1438 // Validate the sequence number.
1440 Seq
= NTOHL (Head
->Seq
);
1441 if (!(TCP_SEQ_LEQ (Tcb
->SndUna
, Seq
) && TCP_SEQ_LT (Seq
, Tcb
->SndNxt
))) {
1446 IcmpErrStatus
= IpIoGetIcmpErrStatus (IcmpErr
, &IcmpErrIsHard
, &IcmpErrNotify
);
1448 if (IcmpErrNotify
) {
1450 SOCK_ERROR (Tcb
->Sk
, IcmpErrStatus
);
1453 if (IcmpErrIsHard
) {