]>
git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c
3 Copyright (c) 2005 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 TCP input process routines.
27 Check whether the sequence number of the incoming segment
30 @param Tcb Pointer to the TCP_CB of this TCP instance.
31 @param Seg Pointer to the incoming segment.
33 @return 1 if the sequence number is acceptable, otherwise 0.
42 return (TCP_SEQ_LEQ (Tcb
->RcvWl2
, Seg
->End
) &&
43 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
+ Tcb
->RcvWnd
));
48 NewReno fast recovery, RFC3782.
50 @param Tcb Pointer to the TCP_CB of this TCP instance.
51 @param Seg Segment that triggers the fast recovery.
66 // Step 1: Three duplicate ACKs and not in fast recovery
68 if (Tcb
->CongestState
!= TCP_CONGEST_RECOVER
) {
71 // Step 1A: Invoking fast retransmission.
73 FlightSize
= TCP_SUB_SEQ (Tcb
->SndNxt
, Tcb
->SndUna
);
75 Tcb
->Ssthresh
= MAX (FlightSize
>> 1, (UINT32
) (2 * Tcb
->SndMss
));
76 Tcb
->Recover
= Tcb
->SndNxt
;
78 Tcb
->CongestState
= TCP_CONGEST_RECOVER
;
79 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
82 // Step 2: Entering fast retransmission
84 TcpRetransmit (Tcb
, Tcb
->SndUna
);
85 Tcb
->CWnd
= Tcb
->Ssthresh
+ 3 * Tcb
->SndMss
;
87 DEBUG ((EFI_D_INFO
, "TcpFastRecover: enter fast retransmission"
88 " for TCB %p, recover point is %d\n", Tcb
, Tcb
->Recover
));
93 // During fast recovery, execute Step 3, 4, 5 of RFC3782
95 if (Seg
->Ack
== Tcb
->SndUna
) {
98 // Step 3: Fast Recovery,
99 // If this is a duplicated ACK, increse Cwnd by SMSS.
102 // Step 4 is skipped here only to be executed later
105 Tcb
->CWnd
+= Tcb
->SndMss
;
106 DEBUG ((EFI_D_INFO
, "TcpFastRecover: received another"
107 " duplicated ACK (%d) for TCB %p\n", Seg
->Ack
, Tcb
));
112 // New data is ACKed, check whether it is a
113 // full ACK or partial ACK
115 if (TCP_SEQ_GEQ (Seg
->Ack
, Tcb
->Recover
)) {
118 // Step 5 - Full ACK:
119 // deflate the congestion window, and exit fast recovery
121 FlightSize
= TCP_SUB_SEQ (Tcb
->SndNxt
, Tcb
->SndUna
);
123 Tcb
->CWnd
= MIN (Tcb
->Ssthresh
, FlightSize
+ Tcb
->SndMss
);
125 Tcb
->CongestState
= TCP_CONGEST_OPEN
;
126 DEBUG ((EFI_D_INFO
, "TcpFastRecover: received a full ACK(%d)"
127 " for TCB %p, exit fast recovery\n", Seg
->Ack
, Tcb
));
132 // Step 5 - Partial ACK:
133 // fast retransmit the first unacknowledge field
134 // , then deflate the CWnd
136 TcpRetransmit (Tcb
, Seg
->Ack
);
137 Acked
= TCP_SUB_SEQ (Seg
->Ack
, Tcb
->SndUna
);
140 // Deflate the CWnd by the amount of new data
141 // ACKed by SEG.ACK. If more than one SMSS data
142 // is ACKed, add back SMSS byte to CWnd after
144 if (Acked
>= Tcb
->SndMss
) {
145 Acked
-= Tcb
->SndMss
;
151 DEBUG ((EFI_D_INFO
, "TcpFastRecover: received a partial"
152 " ACK(%d) for TCB %p\n", Seg
->Ack
, Tcb
));
160 NewReno fast loss recovery, RFC3792.
162 @param Tcb Pointer to the TCP_CB of this TCP instance.
163 @param Seg Segment that triggers the fast loss recovery.
174 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
177 // New data is ACKed, check whether it is a
178 // full ACK or partial ACK
180 if (TCP_SEQ_GEQ (Seg
->Ack
, Tcb
->LossRecover
)) {
183 // Full ACK: exit the loss recovery.
186 Tcb
->CongestState
= TCP_CONGEST_OPEN
;
188 DEBUG ((EFI_D_INFO
, "TcpFastLossRecover: received a "
189 "full ACK(%d) for TCB %p\n", Seg
->Ack
, Tcb
));
195 // fast retransmit the first unacknowledge field.
197 TcpRetransmit (Tcb
, Seg
->Ack
);
198 DEBUG ((EFI_D_INFO
, "TcpFastLossRecover: received a "
199 "partial ACK(%d) for TCB %p\n", Seg
->Ack
, Tcb
));
206 Compute the RTT as specified in RFC2988
208 @param Tcb Pointer to the TCP_CB of this TCP instance.
209 @param Measure Currently measured RTT in heart beats.
223 // Step 2.3: Compute the RTO for subsequent RTT measurement.
225 if (Tcb
->SRtt
!= 0) {
227 Var
= Tcb
->SRtt
- (Measure
<< TCP_RTT_SHIFT
);
233 Tcb
->RttVar
= (3 * Tcb
->RttVar
+ Var
) >> 2;
234 Tcb
->SRtt
= 7 * (Tcb
->SRtt
>> 3) + Measure
;
238 // Step 2.2: compute the first RTT measure
240 Tcb
->SRtt
= Measure
<< TCP_RTT_SHIFT
;
241 Tcb
->RttVar
= Measure
<< (TCP_RTT_SHIFT
- 1);
244 Tcb
->Rto
= (Tcb
->SRtt
+ MAX (8, 4 * Tcb
->RttVar
)) >> TCP_RTT_SHIFT
;
247 // Step 2.4: Limit the RTO to at least 1 second
248 // Step 2.5: Limit the RTO to a maxium value that
249 // is at least 60 second
251 if (Tcb
->Rto
< TCP_RTO_MIN
) {
252 Tcb
->Rto
= TCP_RTO_MIN
;
254 } else if (Tcb
->Rto
> TCP_RTO_MAX
) {
255 Tcb
->Rto
= TCP_RTO_MAX
;
259 DEBUG ((EFI_D_INFO
, "TcpComputeRtt: new RTT for TCB %p"
260 " computed SRTT: %d RTTVAR: %d RTO: %d\n",
261 Tcb
, Tcb
->SRtt
, Tcb
->RttVar
, Tcb
->Rto
));
267 Trim the data, SYN and FIN to fit into the window defined by
270 @param Nbuf Buffer that contains received TCP segment without IP header.
271 @param Left The sequence number of the window's left edge.
272 @param Right The sequence number of the window's right edge.
274 @return 0, the data is successfully trimmed.
288 Seg
= TCPSEG_NETBUF (Nbuf
);
291 // If the segment is completely out of window,
292 // truncate every thing, include SYN and FIN.
294 if (TCP_SEQ_LEQ (Seg
->End
, Left
) || TCP_SEQ_LEQ (Right
, Seg
->Seq
)) {
296 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
297 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
300 NetbufTrim (Nbuf
, Nbuf
->TotalSize
, NET_BUF_HEAD
);
305 // Adjust the buffer header
307 if (TCP_SEQ_LT (Seg
->Seq
, Left
)) {
309 Drop
= TCP_SUB_SEQ (Left
, Seg
->Seq
);
310 Urg
= Seg
->Seq
+ Seg
->Urg
;
313 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
314 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
319 // Adjust the urgent point
321 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
)) {
323 if (TCP_SEQ_LT (Urg
, Seg
->Seq
)) {
325 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_URG
);
327 Seg
->Urg
= (UINT16
) TCP_SUB_SEQ (Urg
, Seg
->Seq
);
332 NetbufTrim (Nbuf
, Drop
, NET_BUF_HEAD
);
337 // Adjust the buffer tail
339 if (TCP_SEQ_GT (Seg
->End
, Right
)) {
341 Drop
= TCP_SUB_SEQ (Seg
->End
, Right
);
344 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
345 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
350 NetbufTrim (Nbuf
, Drop
, NET_BUF_TAIL
);
354 ASSERT (TcpVerifySegment (Nbuf
));
360 Trim off the data outside the tcb's receive window.
362 @param Tcb Pointer to the TCP_CB of this TCP instance.
363 @param Nbuf Pointer to the NET_BUF containing the received tcp segment.
365 @return 0, the data is trimmed.
374 return TcpTrimSegment (Nbuf
, Tcb
->RcvNxt
, Tcb
->RcvWl2
+ Tcb
->RcvWnd
);
379 Process the data and FIN flag, check whether to deliver
380 data to the socket layer.
382 @param Tcb Pointer to the TCP_CB of this TCP instance.
384 @retval 0 No error occurred to deliver data.
385 @retval -1 Error condition occurred. Proper response is to reset the
400 ASSERT (Tcb
&& Tcb
->Sk
);
403 // make sure there is some data queued,
404 // and TCP is in a proper state
406 if (IsListEmpty (&Tcb
->RcvQue
) || !TCP_CONNECTED (Tcb
->State
)) {
412 // Deliver data to the socket layer
414 Entry
= Tcb
->RcvQue
.ForwardLink
;
417 while (Entry
!= &Tcb
->RcvQue
) {
418 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
419 Seg
= TCPSEG_NETBUF (Nbuf
);
421 ASSERT (TcpVerifySegment (Nbuf
));
422 ASSERT (Nbuf
->Tcp
== NULL
);
424 if (TCP_SEQ_GT (Seg
->Seq
, Seq
)) {
428 Entry
= Entry
->ForwardLink
;
432 RemoveEntryList (&Nbuf
->List
);
435 // RFC793 Eighth step: process FIN in sequence
437 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
440 // The peer sends to us junky data after FIN,
441 // reset the connection.
443 if (!IsListEmpty (&Tcb
->RcvQue
)) {
444 DEBUG ((EFI_D_ERROR
, "TcpDeliverData: data received after"
445 " FIN from peer of TCB %p, reset connection\n", Tcb
));
451 DEBUG ((EFI_D_INFO
, "TcpDeliverData: processing FIN "
452 "from peer of TCB %p\n", Tcb
));
454 switch (Tcb
->State
) {
456 case TCP_ESTABLISHED
:
458 TcpSetState (Tcb
, TCP_CLOSE_WAIT
);
463 if (!TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
465 TcpSetState (Tcb
, TCP_CLOSING
);
474 TcpSetState (Tcb
, TCP_TIME_WAIT
);
475 TcpClearAllTimer (Tcb
);
477 if (Tcb
->TimeWaitTimeout
!= 0) {
479 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
482 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
483 "because app disables TIME_WAIT timer for %p\n", Tcb
));
495 // The peer sends to us junk FIN byte. Discard
496 // the buffer then reset the connection
503 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
509 // Don't delay the ack if PUSH flag is on.
511 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_PSH
)) {
513 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
516 if (Nbuf
->TotalSize
) {
519 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
520 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvUp
)) {
522 if (TCP_SEQ_LEQ (Seg
->End
, Tcb
->RcvUp
)) {
523 Urgent
= Nbuf
->TotalSize
;
525 Urgent
= TCP_SUB_SEQ (Tcb
->RcvUp
, Seg
->Seq
) + 1;
529 SockDataRcvd (Tcb
->Sk
, Nbuf
, Urgent
);
532 if (TCP_FIN_RCVD (Tcb
->State
)) {
534 SockNoMoreData (Tcb
->Sk
);
545 Store the data into the reassemble queue.
547 @param Tcb Pointer to the TCP_CB of this TCP instance.
548 @param Nbuf Pointer to the buffer containing the data to be queued.
565 ASSERT (Tcb
&& Nbuf
&& (Nbuf
->Tcp
== NULL
));
569 Seg
= TCPSEG_NETBUF (Nbuf
);
573 // Fast path to process normal case. That is,
574 // no out-of-order segments are received.
576 if (IsListEmpty (Head
)) {
578 InsertTailList (Head
, &Nbuf
->List
);
583 // Find the point to insert the buffer
585 for (Prev
= Head
, Cur
= Head
->ForwardLink
;
587 Prev
= Cur
, Cur
= Cur
->ForwardLink
) {
589 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
591 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
)) {
597 // Check whether the current segment overlaps with the
601 Node
= NET_LIST_USER_STRUCT (Prev
, NET_BUF
, List
);
603 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->End
)) {
605 if (TCP_SEQ_LEQ (Seg
->End
, TCPSEG_NETBUF (Node
)->End
)) {
611 TcpTrimSegment (Nbuf
, TCPSEG_NETBUF (Node
)->End
, Seg
->End
);
615 InsertHeadList (Prev
, &Nbuf
->List
);
617 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
620 // Check the segments after the insert point.
622 while (Cur
!= Head
) {
623 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
625 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->End
, Seg
->End
)) {
627 Cur
= Cur
->ForwardLink
;
629 RemoveEntryList (&Node
->List
);
634 if (TCP_SEQ_LT (TCPSEG_NETBUF (Node
)->Seq
, Seg
->End
)) {
636 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->Seq
, Seg
->Seq
)) {
638 RemoveEntryList (&Nbuf
->List
);
643 TcpTrimSegment (Nbuf
, Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
);
647 Cur
= Cur
->ForwardLink
;
653 Ajust the send queue or the retransmit queue.
655 @param Tcb Pointer to the TCP_CB of this TCP instance.
656 @param Ack The acknowledge seuqence number of the received segment.
673 Cur
= Head
->ForwardLink
;
675 while (Cur
!= Head
) {
676 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
677 Seg
= TCPSEG_NETBUF (Node
);
679 if (TCP_SEQ_GEQ (Seg
->Seq
, Ack
)) {
684 // Remove completely ACKed segments
686 if (TCP_SEQ_LEQ (Seg
->End
, Ack
)) {
687 Cur
= Cur
->ForwardLink
;
689 RemoveEntryList (&Node
->List
);
694 TcpTrimSegment (Node
, Ack
, Seg
->End
);
701 Process the received TCP segments.
703 @param Nbuf Buffer that contains received TCP segment without IP header.
704 @param Src Source address of the segment, or the peer's IP address.
705 @param Dst Destination address of the segment, or the local end's IP
708 @retval 0 Segment is processed successfully. It is either accepted or
709 discarded. But no connection is reset by the segment.
710 @retval -1 A connection is reset by the segment.
729 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
734 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
735 Len
= Nbuf
->TotalSize
- (Head
->HeadLen
<< 2);
737 if ((Head
->HeadLen
< 5) || (Len
< 0) ||
738 TcpChecksum (Nbuf
, NetPseudoHeadChecksum (Src
, Dst
, 6, 0))) {
740 DEBUG ((EFI_D_INFO
, "TcpInput: received an mal-formated packet\n"));
744 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)) {
748 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_FIN
)) {
757 (BOOLEAN
) TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)
760 if ((Tcb
== NULL
) || (Tcb
->State
== TCP_CLOSED
)) {
761 DEBUG ((EFI_D_INFO
, "TcpInput: send reset because no TCB find\n"));
767 Seg
= TcpFormatNetbuf (Tcb
, Nbuf
);
770 // RFC1122 recommended reaction to illegal option
771 // (in fact, an illegal option length) is reset.
773 if (TcpParseOption (Nbuf
->Tcp
, &Option
) == -1) {
774 DEBUG ((EFI_D_ERROR
, "TcpInput: reset the peer because"
775 " of mal-format option for Tcb %p\n", Tcb
));
781 // From now on, the segment is headless
783 NetbufTrim (Nbuf
, (Head
->HeadLen
<< 2), NET_BUF_HEAD
);
787 // TODO: add fast path process here
791 // Process the segment in LISTEN state.
793 if (Tcb
->State
== TCP_LISTEN
) {
795 // First step: Check RST
797 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
798 DEBUG ((EFI_D_WARN
, "TcpInput: discard a reset segment "
799 "for TCB %p in listening\n", Tcb
));
805 // Second step: Check ACK.
806 // Any ACK sent to TCP in LISTEN is reseted.
808 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
809 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of"
810 " segment with ACK for TCB %p in listening\n", Tcb
));
816 // Third step: Check SYN
818 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
820 // create a child TCB to handle the data
824 Tcb
= TcpCloneTcb (Parent
);
826 DEBUG ((EFI_D_ERROR
, "TcpInput: discard a segment because"
827 "failed to clone a child for TCB%x\n", Tcb
));
832 DEBUG ((EFI_D_INFO
, "TcpInput: create a child for TCB %p"
833 " in listening\n", Tcb
));
836 // init the TCB structure
838 Tcb
->LocalEnd
.Ip
= Dst
;
839 Tcb
->LocalEnd
.Port
= Head
->DstPort
;
840 Tcb
->RemoteEnd
.Ip
= Src
;
841 Tcb
->RemoteEnd
.Port
= Head
->SrcPort
;
843 TcpInitTcbLocal (Tcb
);
844 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
846 TcpSetState (Tcb
, TCP_SYN_RCVD
);
847 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
848 TcpTrimInWnd (Tcb
, Nbuf
);
855 } else if (Tcb
->State
== TCP_SYN_SENT
) {
857 // First step: Check ACK bit
859 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
) && (Seg
->Ack
!= Tcb
->Iss
+ 1)) {
861 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of "
862 "wrong ACK received for TCB %p in SYN_SENT\n", Tcb
));
868 // Second step: Check RST bit
870 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
872 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
874 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset by"
875 " peer for TCB%x in SYN_SENT\n", Tcb
));
877 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
878 goto DROP_CONNECTION
;
881 DEBUG ((EFI_D_WARN
, "TcpInput: discard a reset segment "
882 "because of no ACK for TCB%x in SYN_SENT\n", Tcb
));
889 // Third step: Check security and precedence. Skipped
893 // Fourth step: Check SYN. Pay attention to sitimulatous open
895 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
897 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
899 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
901 Tcb
->SndUna
= Seg
->Ack
;
904 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
906 if (TCP_SEQ_GT (Tcb
->SndUna
, Tcb
->Iss
)) {
908 TcpSetState (Tcb
, TCP_ESTABLISHED
);
910 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
911 TcpDeliverData (Tcb
);
913 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
914 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
916 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
917 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
920 TcpTrimInWnd (Tcb
, Nbuf
);
922 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
924 DEBUG ((EFI_D_INFO
, "TcpInput: connection established"
925 " for TCB %p in SYN_SENT\n", Tcb
));
930 // Received a SYN segment without ACK, simultanous open.
932 TcpSetState (Tcb
, TCP_SYN_RCVD
);
934 ASSERT (Tcb
->SndNxt
== Tcb
->Iss
+ 1);
935 TcpAdjustSndQue (Tcb
, Tcb
->SndNxt
);
937 TcpTrimInWnd (Tcb
, Nbuf
);
939 DEBUG ((EFI_D_WARN
, "TcpInput: simultanous open "
940 "for TCB %p in SYN_SENT\n", Tcb
));
950 // Process segment in SYN_RCVD or TCP_CONNECTED states
954 // First step: Check whether SEG.SEQ is acceptable
956 if (!TcpSeqAcceptable (Tcb
, Seg
)) {
957 DEBUG ((EFI_D_WARN
, "TcpInput: sequence acceptance"
958 " test failed for segment of TCB %p\n", Tcb
));
960 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
967 if ((TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
)) &&
968 (Tcb
->RcvWl2
== Seg
->End
) &&
969 !TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
| TCP_FLG_FIN
)) {
971 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
975 // Second step: Check the RST
977 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
979 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset for TCB %p\n", Tcb
));
981 if (Tcb
->State
== TCP_SYN_RCVD
) {
983 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_REFUSED
);
986 // This TCB comes from either a LISTEN TCB,
987 // or active open TCB with simultanous open.
988 // Do NOT signal user CONNECTION refused
989 // if it comes from a LISTEN TCB.
991 } else if ((Tcb
->State
== TCP_ESTABLISHED
) ||
992 (Tcb
->State
== TCP_FIN_WAIT_1
) ||
993 (Tcb
->State
== TCP_FIN_WAIT_2
) ||
994 (Tcb
->State
== TCP_CLOSE_WAIT
)
997 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1001 // TODO: set socket error to CLOSED
1005 goto DROP_CONNECTION
;
1009 // Trim the data and flags.
1011 TcpTrimInWnd (Tcb
, Nbuf
);
1014 // Third step: Check security and precedence, Ignored
1018 // Fourth step: Check the SYN bit.
1020 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1022 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset "
1023 "because received extra SYN for TCB %p\n", Tcb
));
1025 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1026 goto RESET_THEN_DROP
;
1030 // Fifth step: Check the ACK
1032 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
1033 DEBUG ((EFI_D_WARN
, "TcpInput: segment discard because"
1034 " of no ACK for connected TCB %p\n", Tcb
));
1040 if (Tcb
->State
== TCP_SYN_RCVD
) {
1042 if (TCP_SEQ_LT (Tcb
->SndUna
, Seg
->Ack
) &&
1043 TCP_SEQ_LEQ (Seg
->Ack
, Tcb
->SndNxt
)) {
1045 Tcb
->SndWnd
= Seg
->Wnd
;
1046 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1047 Tcb
->SndWl1
= Seg
->Seq
;
1048 Tcb
->SndWl2
= Seg
->Ack
;
1049 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1051 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1052 TcpDeliverData (Tcb
);
1054 DEBUG ((EFI_D_INFO
, "TcpInput: connection established "
1055 " for TCB %p in SYN_RCVD\n", Tcb
));
1058 // Continue the process as ESTABLISHED state
1061 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of"
1062 " wrong ACK for TCB %p in SYN_RCVD\n", Tcb
));
1068 if (TCP_SEQ_LT (Seg
->Ack
, Tcb
->SndUna
)) {
1070 DEBUG ((EFI_D_WARN
, "TcpInput: ignore the out-of-data"
1071 " ACK for connected TCB %p\n", Tcb
));
1075 } else if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndNxt
)) {
1077 DEBUG ((EFI_D_WARN
, "TcpInput: discard segment for "
1078 "future ACK for connected TCB %p\n", Tcb
));
1085 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1087 if (TCP_FLG_ON (Option
.Flag
, TCP_OPTION_RCVD_TS
)) {
1089 // update TsRecent as specified in page 16 RFC1323.
1090 // RcvWl2 equals to the variable "LastAckSent"
1093 if (TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
) &&
1094 TCP_SEQ_LT (Tcb
->RcvWl2
, Seg
->End
)) {
1096 Tcb
->TsRecent
= Option
.TSVal
;
1097 Tcb
->TsRecentAge
= mTcpTick
;
1100 TcpComputeRtt (Tcb
, TCP_SUB_TIME (mTcpTick
, Option
.TSEcr
));
1102 } else if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
1104 ASSERT (Tcb
->CongestState
== TCP_CONGEST_OPEN
);
1106 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1107 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1110 if (Seg
->Ack
== Tcb
->SndNxt
) {
1112 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1115 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
1119 // Count duplicate acks.
1121 if ((Seg
->Ack
== Tcb
->SndUna
) &&
1122 (Tcb
->SndUna
!= Tcb
->SndNxt
) &&
1123 (Seg
->Wnd
== Tcb
->SndWnd
) &&
1133 // Congestion avoidance, fast recovery and fast retransmission.
1135 if (((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && (Tcb
->DupAck
< 3)) ||
1136 (Tcb
->CongestState
== TCP_CONGEST_LOSS
)) {
1138 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1140 if (Tcb
->CWnd
< Tcb
->Ssthresh
) {
1142 Tcb
->CWnd
+= Tcb
->SndMss
;
1145 Tcb
->CWnd
+= MAX (Tcb
->SndMss
* Tcb
->SndMss
/ Tcb
->CWnd
, 1);
1148 Tcb
->CWnd
= MIN (Tcb
->CWnd
, TCP_MAX_WIN
<< Tcb
->SndWndScale
);
1151 if (Tcb
->CongestState
== TCP_CONGEST_LOSS
) {
1152 TcpFastLossRecover (Tcb
, Seg
);
1156 TcpFastRecover (Tcb
, Seg
);
1159 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1161 TcpAdjustSndQue (Tcb
, Seg
->Ack
);
1162 Tcb
->SndUna
= Seg
->Ack
;
1164 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
1165 (TCP_SEQ_LT (Tcb
->SndUp
, Seg
->Ack
))) {
1167 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
1172 // Update window info
1174 if (TCP_SEQ_LT (Tcb
->SndWl1
, Seg
->Seq
) ||
1175 ((Tcb
->SndWl1
== Seg
->Seq
) && TCP_SEQ_LEQ (Tcb
->SndWl2
, Seg
->Ack
))) {
1177 Right
= Seg
->Ack
+ Seg
->Wnd
;
1179 if (TCP_SEQ_LT (Right
, Tcb
->SndWl2
+ Tcb
->SndWnd
)) {
1181 if ((Tcb
->SndWl1
== Seg
->Seq
) &&
1182 (Tcb
->SndWl2
== Seg
->Ack
) &&
1188 DEBUG ((EFI_D_WARN
, "TcpInput: peer shrinks the"
1189 " window for connected TCB %p\n", Tcb
));
1191 if ((Tcb
->CongestState
== TCP_CONGEST_RECOVER
) &&
1192 (TCP_SEQ_LT (Right
, Tcb
->Recover
))) {
1194 Tcb
->Recover
= Right
;
1197 if ((Tcb
->CongestState
== TCP_CONGEST_LOSS
) &&
1198 (TCP_SEQ_LT (Right
, Tcb
->LossRecover
))) {
1200 Tcb
->LossRecover
= Right
;
1203 if (TCP_SEQ_LT (Right
, Tcb
->SndNxt
)) {
1205 Tcb
->SndNxt
= Right
;
1207 if (Right
== Tcb
->SndUna
) {
1209 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1210 TcpSetProbeTimer (Tcb
);
1215 Tcb
->SndWnd
= Seg
->Wnd
;
1216 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1217 Tcb
->SndWl1
= Seg
->Seq
;
1218 Tcb
->SndWl2
= Seg
->Ack
;
1223 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
) &&
1224 (Tcb
->SndUna
== Tcb
->SndNxt
)) {
1226 DEBUG ((EFI_D_INFO
, "TcpInput: local FIN is ACKed by"
1227 " peer for connected TCB %p\n", Tcb
));
1229 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
);
1233 // Transit the state if proper.
1235 switch (Tcb
->State
) {
1236 case TCP_FIN_WAIT_1
:
1238 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1240 TcpSetState (Tcb
, TCP_FIN_WAIT_2
);
1242 TcpClearAllTimer (Tcb
);
1243 TcpSetTimer (Tcb
, TCP_TIMER_FINWAIT2
, Tcb
->FinWait2Timeout
);
1246 case TCP_FIN_WAIT_2
:
1250 case TCP_CLOSE_WAIT
:
1255 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1257 TcpSetState (Tcb
, TCP_TIME_WAIT
);
1259 TcpClearAllTimer (Tcb
);
1261 if (Tcb
->TimeWaitTimeout
!= 0) {
1263 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1266 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
1267 "because app disables TIME_WAIT timer for %p\n", Tcb
));
1276 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1278 TcpSetState (Tcb
, TCP_CLOSED
);
1287 if (Tcb
->TimeWaitTimeout
!= 0) {
1289 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1292 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
1293 "because app disables TIME_WAIT timer for %p\n", Tcb
));
1301 // Sixth step: Check the URG bit.update the Urg point
1302 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1307 TcpSetKeepaliveTimer (Tcb
);
1309 if (TCP_TIMER_ON (Tcb
->EnabledTimer
, TCP_TIMER_PROBE
)) {
1311 TcpClearTimer (Tcb
, TCP_TIMER_PROBE
);
1314 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
) &&
1315 !TCP_FIN_RCVD (Tcb
->State
)) {
1317 DEBUG ((EFI_D_INFO
, "TcpInput: received urgent data "
1318 "from peer for connected TCB %p\n", Tcb
));
1320 Urg
= Seg
->Seq
+ Seg
->Urg
;
1322 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
1323 TCP_SEQ_GT (Urg
, Tcb
->RcvUp
)) {
1329 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
);
1334 // Seventh step: Process the segment data
1336 if (Seg
->End
!= Seg
->Seq
) {
1338 if (TCP_FIN_RCVD (Tcb
->State
)) {
1340 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset because"
1341 " data is lost for connected TCB %p\n", Tcb
));
1343 goto RESET_THEN_DROP
;
1346 if (TCP_LOCAL_CLOSED (Tcb
->State
) && (Nbuf
->TotalSize
!= 0)) {
1347 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset because"
1348 " data is lost for connected TCB %p\n", Tcb
));
1350 goto RESET_THEN_DROP
;
1353 TcpQueueData (Tcb
, Nbuf
);
1354 if (TcpDeliverData (Tcb
) == -1) {
1355 goto RESET_THEN_DROP
;
1358 if (!IsListEmpty (&Tcb
->RcvQue
)) {
1359 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1364 // Eighth step: check the FIN.
1365 // This step is moved to TcpDeliverData. FIN will be
1366 // processed in sequence there. Check the comments in
1367 // the beginning of the file header for information.
1371 // Tcb is a new child of the listening Parent,
1375 Tcb
->Parent
= Parent
;
1379 if ((Tcb
->State
!= TCP_CLOSED
) &&
1380 (!TcpToSendData (Tcb
, 0)) &&
1381 (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || Nbuf
->TotalSize
)) {
1390 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1393 ASSERT (Tcb
&& Tcb
->Sk
);
1402 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1407 // Tcb is a child of Parent, and it doesn't survive
1409 DEBUG ((EFI_D_WARN
, "Tcp4Input: Discard a packet\n"));
1412 if (Parent
&& Tcb
) {
1423 Process the received ICMP error messages for TCP.
1425 @param Nbuf Buffer that contains part of the TCP segment without IP header
1426 truncated from the ICMP error packet.
1427 @param IcmpErr The ICMP error code interpreted from ICMP error packet.
1428 @param Src Source address of the ICMP error message.
1429 @param Dst Destination address of the ICMP error message.
1437 IN ICMP_ERROR IcmpErr
,
1445 EFI_STATUS IcmpErrStatus
;
1446 BOOLEAN IcmpErrIsHard
;
1447 BOOLEAN IcmpErrNotify
;
1449 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
1450 Tcb
= TcpLocateTcb (
1457 if (Tcb
== NULL
|| Tcb
->State
== TCP_CLOSED
) {
1463 // Validate the sequence number.
1465 Seq
= NTOHL (Head
->Seq
);
1466 if (!(TCP_SEQ_LEQ (Tcb
->SndUna
, Seq
) && TCP_SEQ_LT (Seq
, Tcb
->SndNxt
))) {
1471 IcmpErrStatus
= IpIoGetIcmpErrStatus (IcmpErr
, &IcmpErrIsHard
, &IcmpErrNotify
);
1473 if (IcmpErrNotify
) {
1475 SOCK_ERROR (Tcb
->Sk
, IcmpErrStatus
);
1478 if (IcmpErrIsHard
) {