]>
git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c
2 TCP input process routines.
4 Copyright (c) 2005 - 2010, 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
->RcvWl2
, 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_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.
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_INFO
, "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
486 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
492 // Don't delay the ack if PUSH flag is on.
494 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_PSH
)) {
496 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
499 if (Nbuf
->TotalSize
!= 0) {
502 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
503 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvUp
)) {
505 if (TCP_SEQ_LEQ (Seg
->End
, Tcb
->RcvUp
)) {
506 Urgent
= Nbuf
->TotalSize
;
508 Urgent
= TCP_SUB_SEQ (Tcb
->RcvUp
, Seg
->Seq
) + 1;
512 SockDataRcvd (Tcb
->Sk
, Nbuf
, Urgent
);
515 if (TCP_FIN_RCVD (Tcb
->State
)) {
517 SockNoMoreData (Tcb
->Sk
);
528 Store the data into the reassemble queue.
530 @param Tcb Pointer to the TCP_CB of this TCP instance.
531 @param Nbuf Pointer to the buffer containing the data to be queued.
546 ASSERT ((Tcb
!= NULL
) && (Nbuf
!= NULL
) && (Nbuf
->Tcp
== NULL
));
550 Seg
= TCPSEG_NETBUF (Nbuf
);
554 // Fast path to process normal case. That is,
555 // no out-of-order segments are received.
557 if (IsListEmpty (Head
)) {
559 InsertTailList (Head
, &Nbuf
->List
);
564 // Find the point to insert the buffer
566 for (Prev
= Head
, Cur
= Head
->ForwardLink
;
568 Prev
= Cur
, Cur
= Cur
->ForwardLink
) {
570 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
572 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
)) {
578 // Check whether the current segment overlaps with the
582 Node
= NET_LIST_USER_STRUCT (Prev
, NET_BUF
, List
);
584 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->End
)) {
586 if (TCP_SEQ_LEQ (Seg
->End
, TCPSEG_NETBUF (Node
)->End
)) {
592 TcpTrimSegment (Nbuf
, TCPSEG_NETBUF (Node
)->End
, Seg
->End
);
596 InsertHeadList (Prev
, &Nbuf
->List
);
598 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
601 // Check the segments after the insert point.
603 while (Cur
!= Head
) {
604 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
606 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->End
, Seg
->End
)) {
608 Cur
= Cur
->ForwardLink
;
610 RemoveEntryList (&Node
->List
);
615 if (TCP_SEQ_LT (TCPSEG_NETBUF (Node
)->Seq
, Seg
->End
)) {
617 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->Seq
, Seg
->Seq
)) {
619 RemoveEntryList (&Nbuf
->List
);
624 TcpTrimSegment (Nbuf
, Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
);
628 Cur
= Cur
->ForwardLink
;
634 Ajust the send queue or the retransmit queue.
636 @param Tcb Pointer to the TCP_CB of this TCP instance.
637 @param Ack The acknowledge seuqence number of the received segment.
652 Cur
= Head
->ForwardLink
;
654 while (Cur
!= Head
) {
655 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
656 Seg
= TCPSEG_NETBUF (Node
);
658 if (TCP_SEQ_GEQ (Seg
->Seq
, Ack
)) {
663 // Remove completely ACKed segments
665 if (TCP_SEQ_LEQ (Seg
->End
, Ack
)) {
666 Cur
= Cur
->ForwardLink
;
668 RemoveEntryList (&Node
->List
);
673 TcpTrimSegment (Node
, Ack
, Seg
->End
);
680 Process the received TCP segments.
682 @param Nbuf Buffer that contains received TCP segment without IP header.
683 @param Src Source address of the segment, or the peer's IP address.
684 @param Dst Destination address of the segment, or the local end's IP
687 @retval 0 Segment is processed successfully. It is either accepted or
688 discarded. But no connection is reset by the segment.
689 @retval -1 A connection is reset by the segment.
708 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
713 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
714 Len
= Nbuf
->TotalSize
- (Head
->HeadLen
<< 2);
716 if ((Head
->HeadLen
< 5) || (Len
< 0) ||
717 (TcpChecksum (Nbuf
, NetPseudoHeadChecksum (Src
, Dst
, 6, 0)) != 0)) {
719 DEBUG ((EFI_D_INFO
, "TcpInput: received an mal-formated packet\n"));
723 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)) {
727 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_FIN
)) {
736 (BOOLEAN
) TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)
739 if ((Tcb
== NULL
) || (Tcb
->State
== TCP_CLOSED
)) {
740 DEBUG ((EFI_D_INFO
, "TcpInput: send reset because no TCB find\n"));
746 Seg
= TcpFormatNetbuf (Tcb
, Nbuf
);
749 // RFC1122 recommended reaction to illegal option
750 // (in fact, an illegal option length) is reset.
752 if (TcpParseOption (Nbuf
->Tcp
, &Option
) == -1) {
753 DEBUG ((EFI_D_ERROR
, "TcpInput: reset the peer because"
754 " of mal-format option for Tcb %p\n", Tcb
));
760 // From now on, the segment is headless
762 NetbufTrim (Nbuf
, (Head
->HeadLen
<< 2), NET_BUF_HEAD
);
766 // Process the segment in LISTEN state.
768 if (Tcb
->State
== TCP_LISTEN
) {
770 // First step: Check RST
772 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
773 DEBUG ((EFI_D_WARN
, "TcpInput: discard a reset segment "
774 "for TCB %p in listening\n", Tcb
));
780 // Second step: Check ACK.
781 // Any ACK sent to TCP in LISTEN is reseted.
783 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
784 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of"
785 " segment with ACK for TCB %p in listening\n", Tcb
));
791 // Third step: Check SYN
793 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
795 // create a child TCB to handle the data
799 Tcb
= TcpCloneTcb (Parent
);
801 DEBUG ((EFI_D_ERROR
, "TcpInput: discard a segment because"
802 " failed to clone a child for TCB%x\n", Tcb
));
807 DEBUG ((EFI_D_INFO
, "TcpInput: create a child for TCB %p"
808 " in listening\n", Tcb
));
811 // init the TCB structure
813 Tcb
->LocalEnd
.Ip
= Dst
;
814 Tcb
->LocalEnd
.Port
= Head
->DstPort
;
815 Tcb
->RemoteEnd
.Ip
= Src
;
816 Tcb
->RemoteEnd
.Port
= Head
->SrcPort
;
818 TcpInitTcbLocal (Tcb
);
819 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
821 TcpSetState (Tcb
, TCP_SYN_RCVD
);
822 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
823 TcpTrimInWnd (Tcb
, Nbuf
);
830 } else if (Tcb
->State
== TCP_SYN_SENT
) {
832 // First step: Check ACK bit
834 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
) && (Seg
->Ack
!= Tcb
->Iss
+ 1)) {
836 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of "
837 "wrong ACK received for TCB %p in SYN_SENT\n", Tcb
));
843 // Second step: Check RST bit
845 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
847 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
849 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset by"
850 " peer for TCB %p in SYN_SENT\n", Tcb
));
852 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
853 goto DROP_CONNECTION
;
856 DEBUG ((EFI_D_WARN
, "TcpInput: discard a reset segment "
857 "because of no ACK for TCB %p in SYN_SENT\n", Tcb
));
864 // Third step: Check security and precedence. Skipped
868 // Fourth step: Check SYN. Pay attention to sitimulatous open
870 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
872 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
874 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
876 Tcb
->SndUna
= Seg
->Ack
;
879 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
881 if (TCP_SEQ_GT (Tcb
->SndUna
, Tcb
->Iss
)) {
883 TcpSetState (Tcb
, TCP_ESTABLISHED
);
885 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
886 TcpDeliverData (Tcb
);
888 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
889 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
891 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
892 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
895 TcpTrimInWnd (Tcb
, Nbuf
);
897 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
899 DEBUG ((EFI_D_INFO
, "TcpInput: connection established"
900 " for TCB %p in SYN_SENT\n", Tcb
));
905 // Received a SYN segment without ACK, simultanous open.
907 TcpSetState (Tcb
, TCP_SYN_RCVD
);
909 ASSERT (Tcb
->SndNxt
== Tcb
->Iss
+ 1);
910 TcpAdjustSndQue (Tcb
, Tcb
->SndNxt
);
912 TcpTrimInWnd (Tcb
, Nbuf
);
914 DEBUG ((EFI_D_WARN
, "TcpInput: simultanous open "
915 "for TCB %p in SYN_SENT\n", Tcb
));
925 // Process segment in SYN_RCVD or TCP_CONNECTED states
929 // Clear probe timer since the RecvWindow is opened.
931 if (Tcb
->ProbeTimerOn
&& (Seg
->Wnd
!= 0)) {
932 TcpClearTimer (Tcb
, TCP_TIMER_PROBE
);
933 Tcb
->ProbeTimerOn
= FALSE
;
937 // First step: Check whether SEG.SEQ is acceptable
939 if (TcpSeqAcceptable (Tcb
, Seg
) == 0) {
940 DEBUG ((EFI_D_WARN
, "TcpInput: sequence acceptance"
941 " test failed for segment of TCB %p\n", Tcb
));
943 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
950 if ((TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
)) &&
951 (Tcb
->RcvWl2
== Seg
->End
) &&
952 !TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
| TCP_FLG_FIN
)) {
954 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
958 // Second step: Check the RST
960 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
962 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset for TCB %p\n", Tcb
));
964 if (Tcb
->State
== TCP_SYN_RCVD
) {
966 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_REFUSED
);
969 // This TCB comes from either a LISTEN TCB,
970 // or active open TCB with simultanous open.
971 // Do NOT signal user CONNECTION refused
972 // if it comes from a LISTEN TCB.
974 } else if ((Tcb
->State
== TCP_ESTABLISHED
) ||
975 (Tcb
->State
== TCP_FIN_WAIT_1
) ||
976 (Tcb
->State
== TCP_FIN_WAIT_2
) ||
977 (Tcb
->State
== TCP_CLOSE_WAIT
)) {
979 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
985 goto DROP_CONNECTION
;
989 // Trim the data and flags.
991 TcpTrimInWnd (Tcb
, Nbuf
);
994 // Third step: Check security and precedence, Ignored
998 // Fourth step: Check the SYN bit.
1000 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1002 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset "
1003 "because received extra SYN for TCB %p\n", Tcb
));
1005 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1006 goto RESET_THEN_DROP
;
1010 // Fifth step: Check the ACK
1012 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
1013 DEBUG ((EFI_D_WARN
, "TcpInput: segment discard because"
1014 " of no ACK for connected TCB %p\n", Tcb
));
1020 if (Tcb
->State
== TCP_SYN_RCVD
) {
1022 if (TCP_SEQ_LT (Tcb
->SndUna
, Seg
->Ack
) &&
1023 TCP_SEQ_LEQ (Seg
->Ack
, Tcb
->SndNxt
)) {
1025 Tcb
->SndWnd
= Seg
->Wnd
;
1026 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1027 Tcb
->SndWl1
= Seg
->Seq
;
1028 Tcb
->SndWl2
= Seg
->Ack
;
1029 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1031 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1032 TcpDeliverData (Tcb
);
1034 DEBUG ((EFI_D_INFO
, "TcpInput: connection established "
1035 " for TCB %p in SYN_RCVD\n", Tcb
));
1038 // Continue the process as ESTABLISHED state
1041 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of"
1042 " wrong ACK for TCB %p in SYN_RCVD\n", Tcb
));
1048 if (TCP_SEQ_LT (Seg
->Ack
, Tcb
->SndUna
)) {
1050 DEBUG ((EFI_D_WARN
, "TcpInput: ignore the out-of-data"
1051 " ACK for connected TCB %p\n", Tcb
));
1055 } else if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndNxt
)) {
1057 DEBUG ((EFI_D_WARN
, "TcpInput: discard segment for "
1058 "future ACK for connected TCB %p\n", Tcb
));
1065 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1067 if (TCP_FLG_ON (Option
.Flag
, TCP_OPTION_RCVD_TS
)) {
1069 // update TsRecent as specified in page 16 RFC1323.
1070 // RcvWl2 equals to the variable "LastAckSent"
1073 if (TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
) &&
1074 TCP_SEQ_LT (Tcb
->RcvWl2
, Seg
->End
)) {
1076 Tcb
->TsRecent
= Option
.TSVal
;
1077 Tcb
->TsRecentAge
= mTcpTick
;
1080 TcpComputeRtt (Tcb
, TCP_SUB_TIME (mTcpTick
, Option
.TSEcr
));
1082 } else if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
1084 ASSERT (Tcb
->CongestState
== TCP_CONGEST_OPEN
);
1086 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1087 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1090 if (Seg
->Ack
== Tcb
->SndNxt
) {
1092 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1095 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
1099 // Count duplicate acks.
1101 if ((Seg
->Ack
== Tcb
->SndUna
) &&
1102 (Tcb
->SndUna
!= Tcb
->SndNxt
) &&
1103 (Seg
->Wnd
== Tcb
->SndWnd
) &&
1113 // Congestion avoidance, fast recovery and fast retransmission.
1115 if (((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && (Tcb
->DupAck
< 3)) ||
1116 (Tcb
->CongestState
== TCP_CONGEST_LOSS
)) {
1118 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1120 if (Tcb
->CWnd
< Tcb
->Ssthresh
) {
1122 Tcb
->CWnd
+= Tcb
->SndMss
;
1125 Tcb
->CWnd
+= MAX (Tcb
->SndMss
* Tcb
->SndMss
/ Tcb
->CWnd
, 1);
1128 Tcb
->CWnd
= MIN (Tcb
->CWnd
, TCP_MAX_WIN
<< Tcb
->SndWndScale
);
1131 if (Tcb
->CongestState
== TCP_CONGEST_LOSS
) {
1132 TcpFastLossRecover (Tcb
, Seg
);
1136 TcpFastRecover (Tcb
, Seg
);
1139 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1141 TcpAdjustSndQue (Tcb
, Seg
->Ack
);
1142 Tcb
->SndUna
= Seg
->Ack
;
1144 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
1145 TCP_SEQ_LT (Tcb
->SndUp
, Seg
->Ack
)) {
1147 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
1152 // Update window info
1154 if (TCP_SEQ_LT (Tcb
->SndWl1
, Seg
->Seq
) ||
1155 ((Tcb
->SndWl1
== Seg
->Seq
) && TCP_SEQ_LEQ (Tcb
->SndWl2
, Seg
->Ack
))) {
1157 Right
= Seg
->Ack
+ Seg
->Wnd
;
1159 if (TCP_SEQ_LT (Right
, Tcb
->SndWl2
+ Tcb
->SndWnd
)) {
1161 if ((Tcb
->SndWl1
== Seg
->Seq
) &&
1162 (Tcb
->SndWl2
== Seg
->Ack
) &&
1168 DEBUG ((EFI_D_WARN
, "TcpInput: peer shrinks the"
1169 " window for connected TCB %p\n", Tcb
));
1171 if ((Tcb
->CongestState
== TCP_CONGEST_RECOVER
) &&
1172 (TCP_SEQ_LT (Right
, Tcb
->Recover
))) {
1174 Tcb
->Recover
= Right
;
1177 if ((Tcb
->CongestState
== TCP_CONGEST_LOSS
) &&
1178 (TCP_SEQ_LT (Right
, Tcb
->LossRecover
))) {
1180 Tcb
->LossRecover
= Right
;
1183 if (TCP_SEQ_LT (Right
, Tcb
->SndNxt
)) {
1185 Tcb
->SndNxt
= Right
;
1187 if (Right
== Tcb
->SndUna
) {
1189 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1190 TcpSetProbeTimer (Tcb
);
1195 Tcb
->SndWnd
= Seg
->Wnd
;
1196 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1197 Tcb
->SndWl1
= Seg
->Seq
;
1198 Tcb
->SndWl2
= Seg
->Ack
;
1203 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
) &&
1204 (Tcb
->SndUna
== Tcb
->SndNxt
)) {
1206 DEBUG ((EFI_D_INFO
, "TcpInput: local FIN is ACKed by"
1207 " peer for connected TCB %p\n", Tcb
));
1209 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
);
1213 // Transit the state if proper.
1215 switch (Tcb
->State
) {
1216 case TCP_FIN_WAIT_1
:
1218 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1220 TcpSetState (Tcb
, TCP_FIN_WAIT_2
);
1222 TcpClearAllTimer (Tcb
);
1223 TcpSetTimer (Tcb
, TCP_TIMER_FINWAIT2
, Tcb
->FinWait2Timeout
);
1226 case TCP_FIN_WAIT_2
:
1230 case TCP_CLOSE_WAIT
:
1235 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1237 TcpSetState (Tcb
, TCP_TIME_WAIT
);
1239 TcpClearAllTimer (Tcb
);
1241 if (Tcb
->TimeWaitTimeout
!= 0) {
1243 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1246 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
1247 "because app disables TIME_WAIT timer for %p\n", Tcb
));
1256 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1258 TcpSetState (Tcb
, TCP_CLOSED
);
1267 if (Tcb
->TimeWaitTimeout
!= 0) {
1269 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1272 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
1273 "because app disables TIME_WAIT timer for %p\n", Tcb
));
1284 // Sixth step: Check the URG bit.update the Urg point
1285 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1290 TcpSetKeepaliveTimer (Tcb
);
1292 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
) &&
1293 !TCP_FIN_RCVD (Tcb
->State
)) {
1295 DEBUG ((EFI_D_INFO
, "TcpInput: received urgent data "
1296 "from peer for connected TCB %p\n", Tcb
));
1298 Urg
= Seg
->Seq
+ Seg
->Urg
;
1300 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
1301 TCP_SEQ_GT (Urg
, Tcb
->RcvUp
)) {
1307 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
);
1312 // Seventh step: Process the segment data
1314 if (Seg
->End
!= Seg
->Seq
) {
1316 if (TCP_FIN_RCVD (Tcb
->State
)) {
1318 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset because"
1319 " data is lost for connected TCB %p\n", Tcb
));
1321 goto RESET_THEN_DROP
;
1324 if (TCP_LOCAL_CLOSED (Tcb
->State
) && (Nbuf
->TotalSize
!= 0)) {
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 TcpQueueData (Tcb
, Nbuf
);
1332 if (TcpDeliverData (Tcb
) == -1) {
1333 goto RESET_THEN_DROP
;
1336 if (!IsListEmpty (&Tcb
->RcvQue
)) {
1337 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1342 // Eighth step: check the FIN.
1343 // This step is moved to TcpDeliverData. FIN will be
1344 // processed in sequence there. Check the comments in
1345 // the beginning of the file header for information.
1349 // Tcb is a new child of the listening Parent,
1352 if (Parent
!= NULL
) {
1353 Tcb
->Parent
= Parent
;
1357 if ((Tcb
->State
!= TCP_CLOSED
) &&
1358 (TcpToSendData (Tcb
, 0) == 0) &&
1359 (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || (Nbuf
->TotalSize
!= 0))) {
1368 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1371 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
1380 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1385 // Tcb is a child of Parent, and it doesn't survive
1387 DEBUG ((EFI_D_WARN
, "Tcp4Input: Discard a packet\n"));
1390 if ((Parent
!= NULL
) && (Tcb
!= NULL
)) {
1392 ASSERT (Tcb
->Sk
!= NULL
);
1401 Process the received ICMP error messages for TCP.
1403 @param Nbuf Buffer that contains part of the TCP segment without IP header
1404 truncated from the ICMP error packet.
1405 @param IcmpErr The ICMP error code interpreted from ICMP error packet.
1406 @param Src Source address of the ICMP error message.
1407 @param Dst Destination address of the ICMP error message.
1421 EFI_STATUS IcmpErrStatus
;
1422 BOOLEAN IcmpErrIsHard
;
1423 BOOLEAN IcmpErrNotify
;
1425 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
1426 Tcb
= TcpLocateTcb (
1433 if (Tcb
== NULL
|| Tcb
->State
== TCP_CLOSED
) {
1439 // Validate the sequence number.
1441 Seq
= NTOHL (Head
->Seq
);
1442 if (!(TCP_SEQ_LEQ (Tcb
->SndUna
, Seq
) && TCP_SEQ_LT (Seq
, Tcb
->SndNxt
))) {
1447 IcmpErrStatus
= IpIoGetIcmpErrStatus (
1454 if (IcmpErrNotify
) {
1456 SOCK_ERROR (Tcb
->Sk
, IcmpErrStatus
);
1459 if (IcmpErrIsHard
) {