]>
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 is acceptable.
29 @param Tcb Pointer to the TCP_CB of this TCP instance.
30 @param Seg Pointer to the incoming segment.
32 @retval 1 The sequence number is acceptable.
33 @retval 0 The sequence number is not acceptable.
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.
64 // Step 1: Three duplicate ACKs and not in fast recovery
66 if (Tcb
->CongestState
!= TCP_CONGEST_RECOVER
) {
69 // Step 1A: Invoking fast retransmission.
71 FlightSize
= TCP_SUB_SEQ (Tcb
->SndNxt
, Tcb
->SndUna
);
73 Tcb
->Ssthresh
= MAX (FlightSize
>> 1, (UINT32
) (2 * Tcb
->SndMss
));
74 Tcb
->Recover
= Tcb
->SndNxt
;
76 Tcb
->CongestState
= TCP_CONGEST_RECOVER
;
77 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
80 // Step 2: Entering fast retransmission
82 TcpRetransmit (Tcb
, Tcb
->SndUna
);
83 Tcb
->CWnd
= Tcb
->Ssthresh
+ 3 * Tcb
->SndMss
;
85 DEBUG ((EFI_D_INFO
, "TcpFastRecover: enter fast retransmission"
86 " for TCB %p, recover point is %d\n", Tcb
, Tcb
->Recover
));
91 // During fast recovery, execute Step 3, 4, 5 of RFC3782
93 if (Seg
->Ack
== Tcb
->SndUna
) {
96 // Step 3: Fast Recovery,
97 // If this is a duplicated ACK, increse Cwnd by SMSS.
100 // Step 4 is skipped here only to be executed later
103 Tcb
->CWnd
+= Tcb
->SndMss
;
104 DEBUG ((EFI_D_INFO
, "TcpFastRecover: received another"
105 " duplicated ACK (%d) for TCB %p\n", Seg
->Ack
, Tcb
));
110 // New data is ACKed, check whether it is a
111 // full ACK or partial ACK
113 if (TCP_SEQ_GEQ (Seg
->Ack
, Tcb
->Recover
)) {
116 // Step 5 - Full ACK:
117 // deflate the congestion window, and exit fast recovery
119 FlightSize
= TCP_SUB_SEQ (Tcb
->SndNxt
, Tcb
->SndUna
);
121 Tcb
->CWnd
= MIN (Tcb
->Ssthresh
, FlightSize
+ Tcb
->SndMss
);
123 Tcb
->CongestState
= TCP_CONGEST_OPEN
;
124 DEBUG ((EFI_D_INFO
, "TcpFastRecover: received a full ACK(%d)"
125 " for TCB %p, exit fast recovery\n", Seg
->Ack
, Tcb
));
130 // Step 5 - Partial ACK:
131 // fast retransmit the first unacknowledge field
132 // , then deflate the CWnd
134 TcpRetransmit (Tcb
, Seg
->Ack
);
135 Acked
= TCP_SUB_SEQ (Seg
->Ack
, Tcb
->SndUna
);
138 // Deflate the CWnd by the amount of new data
139 // ACKed by SEG.ACK. If more than one SMSS data
140 // is ACKed, add back SMSS byte to CWnd after
142 if (Acked
>= Tcb
->SndMss
) {
143 Acked
-= Tcb
->SndMss
;
149 DEBUG ((EFI_D_INFO
, "TcpFastRecover: received a partial"
150 " ACK(%d) for TCB %p\n", Seg
->Ack
, Tcb
));
158 NewReno fast loss recovery, RFC3792.
160 @param Tcb Pointer to the TCP_CB of this TCP instance.
161 @param Seg Segment that triggers the fast loss recovery.
170 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
173 // New data is ACKed, check whether it is a
174 // full ACK or partial ACK
176 if (TCP_SEQ_GEQ (Seg
->Ack
, Tcb
->LossRecover
)) {
179 // Full ACK: exit the loss recovery.
182 Tcb
->CongestState
= TCP_CONGEST_OPEN
;
184 DEBUG ((EFI_D_INFO
, "TcpFastLossRecover: received a "
185 "full ACK(%d) for TCB %p\n", Seg
->Ack
, Tcb
));
191 // fast retransmit the first unacknowledge field.
193 TcpRetransmit (Tcb
, Seg
->Ack
);
194 DEBUG ((EFI_D_INFO
, "TcpFastLossRecover: received a "
195 "partial ACK(%d) for TCB %p\n", Seg
->Ack
, Tcb
));
202 Compute the RTT as specified in RFC2988.
204 @param Tcb Pointer to the TCP_CB of this TCP instance.
205 @param Measure Currently measured RTT in heart beats.
217 // Step 2.3: Compute the RTO for subsequent RTT measurement.
219 if (Tcb
->SRtt
!= 0) {
221 Var
= Tcb
->SRtt
- (Measure
<< TCP_RTT_SHIFT
);
227 Tcb
->RttVar
= (3 * Tcb
->RttVar
+ Var
) >> 2;
228 Tcb
->SRtt
= 7 * (Tcb
->SRtt
>> 3) + Measure
;
232 // Step 2.2: compute the first RTT measure
234 Tcb
->SRtt
= Measure
<< TCP_RTT_SHIFT
;
235 Tcb
->RttVar
= Measure
<< (TCP_RTT_SHIFT
- 1);
238 Tcb
->Rto
= (Tcb
->SRtt
+ MAX (8, 4 * Tcb
->RttVar
)) >> TCP_RTT_SHIFT
;
241 // Step 2.4: Limit the RTO to at least 1 second
242 // Step 2.5: Limit the RTO to a maxium value that
243 // is at least 60 second
245 if (Tcb
->Rto
< TCP_RTO_MIN
) {
246 Tcb
->Rto
= TCP_RTO_MIN
;
248 } else if (Tcb
->Rto
> TCP_RTO_MAX
) {
249 Tcb
->Rto
= TCP_RTO_MAX
;
253 DEBUG ((EFI_D_INFO
, "TcpComputeRtt: new RTT for TCB %p"
254 " computed SRTT: %d RTTVAR: %d RTO: %d\n",
255 Tcb
, Tcb
->SRtt
, Tcb
->RttVar
, Tcb
->Rto
));
261 Trim the data, SYN and FIN to fit into the window defined by Left and Right.
263 @param Nbuf Buffer that contains received TCP segment without IP header.
264 @param Left The sequence number of the window's left edge.
265 @param Right The sequence number of the window's right edge.
267 @return 0 The data is successfully trimmed.
281 Seg
= TCPSEG_NETBUF (Nbuf
);
284 // If the segment is completely out of window,
285 // truncate every thing, include SYN and FIN.
287 if (TCP_SEQ_LEQ (Seg
->End
, Left
) || TCP_SEQ_LEQ (Right
, Seg
->Seq
)) {
289 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
290 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
293 NetbufTrim (Nbuf
, Nbuf
->TotalSize
, NET_BUF_HEAD
);
298 // Adjust the buffer header
300 if (TCP_SEQ_LT (Seg
->Seq
, Left
)) {
302 Drop
= TCP_SUB_SEQ (Left
, Seg
->Seq
);
303 Urg
= Seg
->Seq
+ Seg
->Urg
;
306 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
307 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
312 // Adjust the urgent point
314 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
)) {
316 if (TCP_SEQ_LT (Urg
, Seg
->Seq
)) {
318 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_URG
);
320 Seg
->Urg
= (UINT16
) TCP_SUB_SEQ (Urg
, Seg
->Seq
);
325 NetbufTrim (Nbuf
, Drop
, NET_BUF_HEAD
);
330 // Adjust the buffer tail
332 if (TCP_SEQ_GT (Seg
->End
, Right
)) {
334 Drop
= TCP_SUB_SEQ (Seg
->End
, Right
);
337 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
338 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
343 NetbufTrim (Nbuf
, Drop
, NET_BUF_TAIL
);
347 ASSERT (TcpVerifySegment (Nbuf
) != 0);
353 Trim off the data outside the tcb's receive window.
355 @param Tcb Pointer to the TCP_CB of this TCP instance.
356 @param Nbuf Pointer to the NET_BUF containing the received tcp segment.
358 @return 0 The data is trimmed.
367 return TcpTrimSegment (Nbuf
, Tcb
->RcvNxt
, Tcb
->RcvWl2
+ Tcb
->RcvWnd
);
372 Process the data and FIN flag, check whether to deliver
373 data to the socket layer.
375 @param Tcb Pointer to the TCP_CB of this TCP instance.
377 @retval 0 No error occurred to deliver data.
378 @retval -1 Error condition occurred. Proper response is to reset the
393 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
396 // make sure there is some data queued,
397 // and TCP is in a proper state
399 if (IsListEmpty (&Tcb
->RcvQue
) || !TCP_CONNECTED (Tcb
->State
)) {
405 // Deliver data to the socket layer
407 Entry
= Tcb
->RcvQue
.ForwardLink
;
410 while (Entry
!= &Tcb
->RcvQue
) {
411 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
412 Seg
= TCPSEG_NETBUF (Nbuf
);
414 ASSERT (TcpVerifySegment (Nbuf
) != 0);
415 ASSERT (Nbuf
->Tcp
== NULL
);
417 if (TCP_SEQ_GT (Seg
->Seq
, Seq
)) {
421 Entry
= Entry
->ForwardLink
;
425 RemoveEntryList (&Nbuf
->List
);
428 // RFC793 Eighth step: process FIN in sequence
430 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
433 // The peer sends to us junky data after FIN,
434 // reset the connection.
436 if (!IsListEmpty (&Tcb
->RcvQue
)) {
437 DEBUG ((EFI_D_ERROR
, "TcpDeliverData: data received after"
438 " FIN from peer of TCB %p, reset connection\n", Tcb
));
444 DEBUG ((EFI_D_INFO
, "TcpDeliverData: processing FIN "
445 "from peer of TCB %p\n", Tcb
));
447 switch (Tcb
->State
) {
449 case TCP_ESTABLISHED
:
451 TcpSetState (Tcb
, TCP_CLOSE_WAIT
);
456 if (!TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
458 TcpSetState (Tcb
, TCP_CLOSING
);
467 TcpSetState (Tcb
, TCP_TIME_WAIT
);
468 TcpClearAllTimer (Tcb
);
470 if (Tcb
->TimeWaitTimeout
!= 0) {
472 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
475 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
476 "because app disables TIME_WAIT timer for %p\n", Tcb
));
488 // The peer sends to us junk FIN byte. Discard
489 // the buffer then reset the connection
496 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
502 // Don't delay the ack if PUSH flag is on.
504 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_PSH
)) {
506 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
509 if (Nbuf
->TotalSize
) {
512 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
513 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvUp
)) {
515 if (TCP_SEQ_LEQ (Seg
->End
, Tcb
->RcvUp
)) {
516 Urgent
= Nbuf
->TotalSize
;
518 Urgent
= TCP_SUB_SEQ (Tcb
->RcvUp
, Seg
->Seq
) + 1;
522 SockDataRcvd (Tcb
->Sk
, Nbuf
, Urgent
);
525 if (TCP_FIN_RCVD (Tcb
->State
)) {
527 SockNoMoreData (Tcb
->Sk
);
538 Store the data into the reassemble queue.
540 @param Tcb Pointer to the TCP_CB of this TCP instance.
541 @param Nbuf Pointer to the buffer containing the data to be queued.
556 ASSERT ((Tcb
!= NULL
) && (Nbuf
!= NULL
) && (Nbuf
->Tcp
== NULL
));
560 Seg
= TCPSEG_NETBUF (Nbuf
);
564 // Fast path to process normal case. That is,
565 // no out-of-order segments are received.
567 if (IsListEmpty (Head
)) {
569 InsertTailList (Head
, &Nbuf
->List
);
574 // Find the point to insert the buffer
576 for (Prev
= Head
, Cur
= Head
->ForwardLink
;
578 Prev
= Cur
, Cur
= Cur
->ForwardLink
) {
580 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
582 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
)) {
588 // Check whether the current segment overlaps with the
592 Node
= NET_LIST_USER_STRUCT (Prev
, NET_BUF
, List
);
594 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->End
)) {
596 if (TCP_SEQ_LEQ (Seg
->End
, TCPSEG_NETBUF (Node
)->End
)) {
602 TcpTrimSegment (Nbuf
, TCPSEG_NETBUF (Node
)->End
, Seg
->End
);
606 InsertHeadList (Prev
, &Nbuf
->List
);
608 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
611 // Check the segments after the insert point.
613 while (Cur
!= Head
) {
614 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
616 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->End
, Seg
->End
)) {
618 Cur
= Cur
->ForwardLink
;
620 RemoveEntryList (&Node
->List
);
625 if (TCP_SEQ_LT (TCPSEG_NETBUF (Node
)->Seq
, Seg
->End
)) {
627 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->Seq
, Seg
->Seq
)) {
629 RemoveEntryList (&Nbuf
->List
);
634 TcpTrimSegment (Nbuf
, Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
);
638 Cur
= Cur
->ForwardLink
;
644 Ajust the send queue or the retransmit queue.
646 @param Tcb Pointer to the TCP_CB of this TCP instance.
647 @param Ack The acknowledge seuqence number of the received segment.
662 Cur
= Head
->ForwardLink
;
664 while (Cur
!= Head
) {
665 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
666 Seg
= TCPSEG_NETBUF (Node
);
668 if (TCP_SEQ_GEQ (Seg
->Seq
, Ack
)) {
673 // Remove completely ACKed segments
675 if (TCP_SEQ_LEQ (Seg
->End
, Ack
)) {
676 Cur
= Cur
->ForwardLink
;
678 RemoveEntryList (&Node
->List
);
683 TcpTrimSegment (Node
, Ack
, Seg
->End
);
690 Process the received TCP segments.
692 @param Nbuf Buffer that contains received TCP segment without IP header.
693 @param Src Source address of the segment, or the peer's IP address.
694 @param Dst Destination address of the segment, or the local end's IP
697 @retval 0 Segment is processed successfully. It is either accepted or
698 discarded. But no connection is reset by the segment.
699 @retval -1 A connection is reset by the segment.
718 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
723 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
724 Len
= Nbuf
->TotalSize
- (Head
->HeadLen
<< 2);
726 if ((Head
->HeadLen
< 5) || (Len
< 0) ||
727 (TcpChecksum (Nbuf
, NetPseudoHeadChecksum (Src
, Dst
, 6, 0)) != 0)) {
729 DEBUG ((EFI_D_INFO
, "TcpInput: received an mal-formated packet\n"));
733 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)) {
737 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_FIN
)) {
746 (BOOLEAN
) TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)
749 if ((Tcb
== NULL
) || (Tcb
->State
== TCP_CLOSED
)) {
750 DEBUG ((EFI_D_INFO
, "TcpInput: send reset because no TCB find\n"));
756 Seg
= TcpFormatNetbuf (Tcb
, Nbuf
);
759 // RFC1122 recommended reaction to illegal option
760 // (in fact, an illegal option length) is reset.
762 if (TcpParseOption (Nbuf
->Tcp
, &Option
) == -1) {
763 DEBUG ((EFI_D_ERROR
, "TcpInput: reset the peer because"
764 " of mal-format option for Tcb %p\n", Tcb
));
770 // From now on, the segment is headless
772 NetbufTrim (Nbuf
, (Head
->HeadLen
<< 2), NET_BUF_HEAD
);
776 // TODO: add fast path process here
780 // Process the segment in LISTEN state.
782 if (Tcb
->State
== TCP_LISTEN
) {
784 // First step: Check RST
786 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
787 DEBUG ((EFI_D_WARN
, "TcpInput: discard a reset segment "
788 "for TCB %p in listening\n", Tcb
));
794 // Second step: Check ACK.
795 // Any ACK sent to TCP in LISTEN is reseted.
797 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
798 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of"
799 " segment with ACK for TCB %p in listening\n", Tcb
));
805 // Third step: Check SYN
807 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
809 // create a child TCB to handle the data
813 Tcb
= TcpCloneTcb (Parent
);
815 DEBUG ((EFI_D_ERROR
, "TcpInput: discard a segment because"
816 "failed to clone a child for TCB%x\n", Tcb
));
821 DEBUG ((EFI_D_INFO
, "TcpInput: create a child for TCB %p"
822 " in listening\n", Tcb
));
825 // init the TCB structure
827 Tcb
->LocalEnd
.Ip
= Dst
;
828 Tcb
->LocalEnd
.Port
= Head
->DstPort
;
829 Tcb
->RemoteEnd
.Ip
= Src
;
830 Tcb
->RemoteEnd
.Port
= Head
->SrcPort
;
832 TcpInitTcbLocal (Tcb
);
833 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
835 TcpSetState (Tcb
, TCP_SYN_RCVD
);
836 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
837 TcpTrimInWnd (Tcb
, Nbuf
);
844 } else if (Tcb
->State
== TCP_SYN_SENT
) {
846 // First step: Check ACK bit
848 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
) && (Seg
->Ack
!= Tcb
->Iss
+ 1)) {
850 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of "
851 "wrong ACK received for TCB %p in SYN_SENT\n", Tcb
));
857 // Second step: Check RST bit
859 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
861 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
863 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset by"
864 " peer for TCB%x in SYN_SENT\n", Tcb
));
866 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
867 goto DROP_CONNECTION
;
870 DEBUG ((EFI_D_WARN
, "TcpInput: discard a reset segment "
871 "because of no ACK for TCB%x in SYN_SENT\n", Tcb
));
878 // Third step: Check security and precedence. Skipped
882 // Fourth step: Check SYN. Pay attention to sitimulatous open
884 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
886 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
888 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
890 Tcb
->SndUna
= Seg
->Ack
;
893 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
895 if (TCP_SEQ_GT (Tcb
->SndUna
, Tcb
->Iss
)) {
897 TcpSetState (Tcb
, TCP_ESTABLISHED
);
899 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
900 TcpDeliverData (Tcb
);
902 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
903 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
905 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
906 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
909 TcpTrimInWnd (Tcb
, Nbuf
);
911 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
913 DEBUG ((EFI_D_INFO
, "TcpInput: connection established"
914 " for TCB %p in SYN_SENT\n", Tcb
));
919 // Received a SYN segment without ACK, simultanous open.
921 TcpSetState (Tcb
, TCP_SYN_RCVD
);
923 ASSERT (Tcb
->SndNxt
== Tcb
->Iss
+ 1);
924 TcpAdjustSndQue (Tcb
, Tcb
->SndNxt
);
926 TcpTrimInWnd (Tcb
, Nbuf
);
928 DEBUG ((EFI_D_WARN
, "TcpInput: simultanous open "
929 "for TCB %p in SYN_SENT\n", Tcb
));
939 // Process segment in SYN_RCVD or TCP_CONNECTED states
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
);
989 // TODO: set socket error to CLOSED
993 goto DROP_CONNECTION
;
997 // Trim the data and flags.
999 TcpTrimInWnd (Tcb
, Nbuf
);
1002 // Third step: Check security and precedence, Ignored
1006 // Fourth step: Check the SYN bit.
1008 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1010 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset "
1011 "because received extra SYN for TCB %p\n", Tcb
));
1013 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1014 goto RESET_THEN_DROP
;
1018 // Fifth step: Check the ACK
1020 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
1021 DEBUG ((EFI_D_WARN
, "TcpInput: segment discard because"
1022 " of no ACK for connected TCB %p\n", Tcb
));
1028 if (Tcb
->State
== TCP_SYN_RCVD
) {
1030 if (TCP_SEQ_LT (Tcb
->SndUna
, Seg
->Ack
) &&
1031 TCP_SEQ_LEQ (Seg
->Ack
, Tcb
->SndNxt
)) {
1033 Tcb
->SndWnd
= Seg
->Wnd
;
1034 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1035 Tcb
->SndWl1
= Seg
->Seq
;
1036 Tcb
->SndWl2
= Seg
->Ack
;
1037 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1039 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1040 TcpDeliverData (Tcb
);
1042 DEBUG ((EFI_D_INFO
, "TcpInput: connection established "
1043 " for TCB %p in SYN_RCVD\n", Tcb
));
1046 // Continue the process as ESTABLISHED state
1049 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of"
1050 " wrong ACK for TCB %p in SYN_RCVD\n", Tcb
));
1056 if (TCP_SEQ_LT (Seg
->Ack
, Tcb
->SndUna
)) {
1058 DEBUG ((EFI_D_WARN
, "TcpInput: ignore the out-of-data"
1059 " ACK for connected TCB %p\n", Tcb
));
1063 } else if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndNxt
)) {
1065 DEBUG ((EFI_D_WARN
, "TcpInput: discard segment for "
1066 "future ACK for connected TCB %p\n", Tcb
));
1073 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1075 if (TCP_FLG_ON (Option
.Flag
, TCP_OPTION_RCVD_TS
)) {
1077 // update TsRecent as specified in page 16 RFC1323.
1078 // RcvWl2 equals to the variable "LastAckSent"
1081 if (TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
) &&
1082 TCP_SEQ_LT (Tcb
->RcvWl2
, Seg
->End
)) {
1084 Tcb
->TsRecent
= Option
.TSVal
;
1085 Tcb
->TsRecentAge
= mTcpTick
;
1088 TcpComputeRtt (Tcb
, TCP_SUB_TIME (mTcpTick
, Option
.TSEcr
));
1090 } else if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
1092 ASSERT (Tcb
->CongestState
== TCP_CONGEST_OPEN
);
1094 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1095 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1098 if (Seg
->Ack
== Tcb
->SndNxt
) {
1100 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1103 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
1107 // Count duplicate acks.
1109 if ((Seg
->Ack
== Tcb
->SndUna
) &&
1110 (Tcb
->SndUna
!= Tcb
->SndNxt
) &&
1111 (Seg
->Wnd
== Tcb
->SndWnd
) &&
1121 // Congestion avoidance, fast recovery and fast retransmission.
1123 if (((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && (Tcb
->DupAck
< 3)) ||
1124 (Tcb
->CongestState
== TCP_CONGEST_LOSS
)) {
1126 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1128 if (Tcb
->CWnd
< Tcb
->Ssthresh
) {
1130 Tcb
->CWnd
+= Tcb
->SndMss
;
1133 Tcb
->CWnd
+= MAX (Tcb
->SndMss
* Tcb
->SndMss
/ Tcb
->CWnd
, 1);
1136 Tcb
->CWnd
= MIN (Tcb
->CWnd
, TCP_MAX_WIN
<< Tcb
->SndWndScale
);
1139 if (Tcb
->CongestState
== TCP_CONGEST_LOSS
) {
1140 TcpFastLossRecover (Tcb
, Seg
);
1144 TcpFastRecover (Tcb
, Seg
);
1147 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1149 TcpAdjustSndQue (Tcb
, Seg
->Ack
);
1150 Tcb
->SndUna
= Seg
->Ack
;
1152 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
1153 TCP_SEQ_LT (Tcb
->SndUp
, Seg
->Ack
)) {
1155 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
1160 // Update window info
1162 if (TCP_SEQ_LT (Tcb
->SndWl1
, Seg
->Seq
) ||
1163 ((Tcb
->SndWl1
== Seg
->Seq
) && TCP_SEQ_LEQ (Tcb
->SndWl2
, Seg
->Ack
))) {
1165 Right
= Seg
->Ack
+ Seg
->Wnd
;
1167 if (TCP_SEQ_LT (Right
, Tcb
->SndWl2
+ Tcb
->SndWnd
)) {
1169 if ((Tcb
->SndWl1
== Seg
->Seq
) &&
1170 (Tcb
->SndWl2
== Seg
->Ack
) &&
1176 DEBUG ((EFI_D_WARN
, "TcpInput: peer shrinks the"
1177 " window for connected TCB %p\n", Tcb
));
1179 if ((Tcb
->CongestState
== TCP_CONGEST_RECOVER
) &&
1180 (TCP_SEQ_LT (Right
, Tcb
->Recover
))) {
1182 Tcb
->Recover
= Right
;
1185 if ((Tcb
->CongestState
== TCP_CONGEST_LOSS
) &&
1186 (TCP_SEQ_LT (Right
, Tcb
->LossRecover
))) {
1188 Tcb
->LossRecover
= Right
;
1191 if (TCP_SEQ_LT (Right
, Tcb
->SndNxt
)) {
1193 Tcb
->SndNxt
= Right
;
1195 if (Right
== Tcb
->SndUna
) {
1197 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1198 TcpSetProbeTimer (Tcb
);
1203 Tcb
->SndWnd
= Seg
->Wnd
;
1204 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1205 Tcb
->SndWl1
= Seg
->Seq
;
1206 Tcb
->SndWl2
= Seg
->Ack
;
1211 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
) &&
1212 (Tcb
->SndUna
== Tcb
->SndNxt
)) {
1214 DEBUG ((EFI_D_INFO
, "TcpInput: local FIN is ACKed by"
1215 " peer for connected TCB %p\n", Tcb
));
1217 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
);
1221 // Transit the state if proper.
1223 switch (Tcb
->State
) {
1224 case TCP_FIN_WAIT_1
:
1226 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1228 TcpSetState (Tcb
, TCP_FIN_WAIT_2
);
1230 TcpClearAllTimer (Tcb
);
1231 TcpSetTimer (Tcb
, TCP_TIMER_FINWAIT2
, Tcb
->FinWait2Timeout
);
1234 case TCP_FIN_WAIT_2
:
1238 case TCP_CLOSE_WAIT
:
1243 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1245 TcpSetState (Tcb
, TCP_TIME_WAIT
);
1247 TcpClearAllTimer (Tcb
);
1249 if (Tcb
->TimeWaitTimeout
!= 0) {
1251 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1254 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
1255 "because app disables TIME_WAIT timer for %p\n", Tcb
));
1264 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1266 TcpSetState (Tcb
, TCP_CLOSED
);
1275 if (Tcb
->TimeWaitTimeout
!= 0) {
1277 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1280 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
1281 "because app disables TIME_WAIT timer for %p\n", Tcb
));
1289 // Sixth step: Check the URG bit.update the Urg point
1290 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1295 TcpSetKeepaliveTimer (Tcb
);
1297 if (TCP_TIMER_ON (Tcb
->EnabledTimer
, TCP_TIMER_PROBE
)) {
1299 TcpClearTimer (Tcb
, TCP_TIMER_PROBE
);
1302 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
) &&
1303 !TCP_FIN_RCVD (Tcb
->State
)) {
1305 DEBUG ((EFI_D_INFO
, "TcpInput: received urgent data "
1306 "from peer for connected TCB %p\n", Tcb
));
1308 Urg
= Seg
->Seq
+ Seg
->Urg
;
1310 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
1311 TCP_SEQ_GT (Urg
, Tcb
->RcvUp
)) {
1317 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
);
1322 // Seventh step: Process the segment data
1324 if (Seg
->End
!= Seg
->Seq
) {
1326 if (TCP_FIN_RCVD (Tcb
->State
)) {
1328 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset because"
1329 " data is lost for connected TCB %p\n", Tcb
));
1331 goto RESET_THEN_DROP
;
1334 if (TCP_LOCAL_CLOSED (Tcb
->State
) && (Nbuf
->TotalSize
!= 0)) {
1335 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset because"
1336 " data is lost for connected TCB %p\n", Tcb
));
1338 goto RESET_THEN_DROP
;
1341 TcpQueueData (Tcb
, Nbuf
);
1342 if (TcpDeliverData (Tcb
) == -1) {
1343 goto RESET_THEN_DROP
;
1346 if (!IsListEmpty (&Tcb
->RcvQue
)) {
1347 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1352 // Eighth step: check the FIN.
1353 // This step is moved to TcpDeliverData. FIN will be
1354 // processed in sequence there. Check the comments in
1355 // the beginning of the file header for information.
1359 // Tcb is a new child of the listening Parent,
1362 if (Parent
!= NULL
) {
1363 Tcb
->Parent
= Parent
;
1367 if ((Tcb
->State
!= TCP_CLOSED
) &&
1368 (TcpToSendData (Tcb
, 0) == 0) &&
1369 (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || Nbuf
->TotalSize
)) {
1378 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1381 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
1390 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1395 // Tcb is a child of Parent, and it doesn't survive
1397 DEBUG ((EFI_D_WARN
, "Tcp4Input: Discard a packet\n"));
1400 if ((Parent
!= NULL
) && (Tcb
!= NULL
)) {
1402 ASSERT (Tcb
->Sk
!= NULL
);
1411 Process the received ICMP error messages for TCP.
1413 @param Nbuf Buffer that contains part of the TCP segment without IP header
1414 truncated from the ICMP error packet.
1415 @param IcmpErr The ICMP error code interpreted from ICMP error packet.
1416 @param Src Source address of the ICMP error message.
1417 @param Dst Destination address of the ICMP error message.
1423 IN ICMP_ERROR IcmpErr
,
1431 EFI_STATUS IcmpErrStatus
;
1432 BOOLEAN IcmpErrIsHard
;
1433 BOOLEAN IcmpErrNotify
;
1435 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
1436 Tcb
= TcpLocateTcb (
1443 if (Tcb
== NULL
|| Tcb
->State
== TCP_CLOSED
) {
1449 // Validate the sequence number.
1451 Seq
= NTOHL (Head
->Seq
);
1452 if (!(TCP_SEQ_LEQ (Tcb
->SndUna
, Seq
) && TCP_SEQ_LT (Seq
, Tcb
->SndNxt
))) {
1457 IcmpErrStatus
= IpIoGetIcmpErrStatus (IcmpErr
, &IcmpErrIsHard
, &IcmpErrNotify
);
1459 if (IcmpErrNotify
) {
1461 SOCK_ERROR (Tcb
->Sk
, IcmpErrStatus
);
1464 if (IcmpErrIsHard
) {