]>
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
= NET_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 TCP4_DEBUG_TRACE (("TcpFastRecover: enter fast retransmission"
88 " for TCB %x, 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 TCP4_DEBUG_TRACE (("TcpFastRecover: received another"
107 " duplicated ACK (%d) for TCB %x\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
= NET_MIN (Tcb
->Ssthresh
, FlightSize
+ Tcb
->SndMss
);
125 Tcb
->CongestState
= TCP_CONGEST_OPEN
;
126 TCP4_DEBUG_TRACE (("TcpFastRecover: received a full ACK(%d)"
127 " for TCB %x, 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 TCP4_DEBUG_TRACE (("TcpFastRecover: received a partial"
152 " ACK(%d) for TCB %x\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 TCP4_DEBUG_TRACE (("TcpFastLossRecover: received a "
189 "full ACK(%d) for TCB %x\n", Seg
->Ack
, Tcb
));
195 // fast retransmit the first unacknowledge field.
197 TcpRetransmit (Tcb
, Seg
->Ack
);
198 TCP4_DEBUG_TRACE (("TcpFastLossRecover: received a "
199 "partial ACK(%d) for TCB %x\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
+ NET_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 TCP4_DEBUG_TRACE (("TcpComputeRtt: new RTT for TCB %x"
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.
289 Seg
= TCPSEG_NETBUF (Nbuf
);
292 // If the segment is completely out of window,
293 // truncate every thing, include SYN and FIN.
295 if (TCP_SEQ_LEQ (Seg
->End
, Left
) || TCP_SEQ_LEQ (Right
, Seg
->Seq
)) {
297 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
298 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
301 NetbufTrim (Nbuf
, Nbuf
->TotalSize
, NET_BUF_HEAD
);
306 // Adjust the buffer header
308 if (TCP_SEQ_LT (Seg
->Seq
, Left
)) {
310 Drop
= TCP_SUB_SEQ (Left
, Seg
->Seq
);
311 Urg
= Seg
->Seq
+ Seg
->Urg
;
314 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
315 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
320 // Adjust the urgent point
322 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
)) {
324 if (TCP_SEQ_LT (Urg
, Seg
->Seq
)) {
326 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_URG
);
328 Seg
->Urg
= (UINT16
) TCP_SUB_SEQ (Urg
, Seg
->Seq
);
333 NetbufTrim (Nbuf
, Drop
, NET_BUF_HEAD
);
338 // Adjust the buffer tail
340 if (TCP_SEQ_GT (Seg
->End
, Right
)) {
342 Drop
= TCP_SUB_SEQ (Seg
->End
, Right
);
345 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
346 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
351 NetbufTrim (Nbuf
, Drop
, NET_BUF_TAIL
);
355 ASSERT (TcpVerifySegment (Nbuf
));
361 Trim off the data outside the tcb's receive window.
363 @param Tcb Pointer to the TCP_CB of this TCP instance.
364 @param Nbuf Pointer to the NET_BUF containing the received tcp segment.
366 @return 0, the data is trimmed.
375 return TcpTrimSegment (Nbuf
, Tcb
->RcvNxt
, Tcb
->RcvWl2
+ Tcb
->RcvWnd
);
380 Process the data and FIN flag, check whether to deliver
381 data to the socket layer.
383 @param Tcb Pointer to the TCP_CB of this TCP instance.
385 @retval 0 No error occurred to deliver data.
386 @retval -1 Error condition occurred. Proper response is to reset the
395 NET_LIST_ENTRY
*Entry
;
401 ASSERT (Tcb
&& Tcb
->Sk
);
404 // make sure there is some data queued,
405 // and TCP is in a proper state
407 if (NetListIsEmpty (&Tcb
->RcvQue
) || !TCP_CONNECTED (Tcb
->State
)) {
413 // Deliver data to the socket layer
415 Entry
= Tcb
->RcvQue
.ForwardLink
;
418 while (Entry
!= &Tcb
->RcvQue
) {
419 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
420 Seg
= TCPSEG_NETBUF (Nbuf
);
422 ASSERT (TcpVerifySegment (Nbuf
));
423 ASSERT (Nbuf
->Tcp
== NULL
);
425 if (TCP_SEQ_GT (Seg
->Seq
, Seq
)) {
429 Entry
= Entry
->ForwardLink
;
433 NetListRemoveEntry (&Nbuf
->List
);
436 // RFC793 Eighth step: process FIN in sequence
438 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
441 // The peer sends to us junky data after FIN,
442 // reset the connection.
444 if (!NetListIsEmpty (&Tcb
->RcvQue
)) {
445 TCP4_DEBUG_ERROR (("TcpDeliverData: data received after"
446 " FIN from peer of TCB %x, reset connection\n", Tcb
));
452 TCP4_DEBUG_TRACE (("TcpDeliverData: processing FIN "
453 "from peer of TCB %x\n", Tcb
));
455 switch (Tcb
->State
) {
457 case TCP_ESTABLISHED
:
459 TcpSetState (Tcb
, TCP_CLOSE_WAIT
);
464 if (!TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
466 TcpSetState (Tcb
, TCP_CLOSING
);
475 TcpSetState (Tcb
, TCP_TIME_WAIT
);
476 TcpClearAllTimer (Tcb
);
478 if (Tcb
->TimeWaitTimeout
!= 0) {
480 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
483 TCP4_DEBUG_WARN (("Connection closed immediately "
484 "because app disables TIME_WAIT timer for %x\n", Tcb
));
496 // The peer sends to us junk FIN byte. Discard
497 // the buffer then reset the connection
504 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
510 // Don't delay the ack if PUSH flag is on.
512 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_PSH
)) {
514 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
517 if (Nbuf
->TotalSize
) {
520 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
521 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvUp
)) {
523 if (TCP_SEQ_LEQ (Seg
->End
, Tcb
->RcvUp
)) {
524 Urgent
= Nbuf
->TotalSize
;
526 Urgent
= TCP_SUB_SEQ (Tcb
->RcvUp
, Seg
->Seq
) + 1;
530 SockDataRcvd (Tcb
->Sk
, Nbuf
, Urgent
);
533 if (TCP_FIN_RCVD (Tcb
->State
)) {
535 SockNoMoreData (Tcb
->Sk
);
546 Store the data into the reassemble queue.
548 @param Tcb Pointer to the TCP_CB of this TCP instance.
549 @param Nbuf Pointer to the buffer containing the data to be queued.
561 NET_LIST_ENTRY
*Head
;
562 NET_LIST_ENTRY
*Prev
;
566 ASSERT (Tcb
&& Nbuf
&& (Nbuf
->Tcp
== NULL
));
570 Seg
= TCPSEG_NETBUF (Nbuf
);
574 // Fast path to process normal case. That is,
575 // no out-of-order segments are received.
577 if (NetListIsEmpty (Head
)) {
579 NetListInsertTail (Head
, &Nbuf
->List
);
584 // Find the point to insert the buffer
586 for (Prev
= Head
, Cur
= Head
->ForwardLink
;
588 Prev
= Cur
, Cur
= Cur
->ForwardLink
) {
590 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
592 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
)) {
598 // Check whether the current segment overlaps with the
602 Node
= NET_LIST_USER_STRUCT (Prev
, NET_BUF
, List
);
604 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->End
)) {
606 if (TCP_SEQ_LEQ (Seg
->End
, TCPSEG_NETBUF (Node
)->End
)) {
612 TcpTrimSegment (Nbuf
, TCPSEG_NETBUF (Node
)->End
, Seg
->End
);
616 NetListInsertHead (Prev
, &Nbuf
->List
);
618 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
621 // Check the segments after the insert point.
623 while (Cur
!= Head
) {
624 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
626 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->End
, Seg
->End
)) {
628 Cur
= Cur
->ForwardLink
;
630 NetListRemoveEntry (&Node
->List
);
635 if (TCP_SEQ_LT (TCPSEG_NETBUF (Node
)->Seq
, Seg
->End
)) {
637 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->Seq
, Seg
->Seq
)) {
639 NetListRemoveEntry (&Nbuf
->List
);
644 TcpTrimSegment (Nbuf
, Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
);
648 Cur
= Cur
->ForwardLink
;
654 Ajust the send queue or the retransmit queue.
656 @param Tcb Pointer to the TCP_CB of this TCP instance.
657 @param Ack The acknowledge seuqence number of the received segment.
668 NET_LIST_ENTRY
*Head
;
674 Cur
= Head
->ForwardLink
;
676 while (Cur
!= Head
) {
677 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
678 Seg
= TCPSEG_NETBUF (Node
);
680 if (TCP_SEQ_GEQ (Seg
->Seq
, Ack
)) {
685 // Remove completely ACKed segments
687 if (TCP_SEQ_LEQ (Seg
->End
, Ack
)) {
688 Cur
= Cur
->ForwardLink
;
690 NetListRemoveEntry (&Node
->List
);
695 TcpTrimSegment (Node
, Ack
, Seg
->End
);
702 Process the received TCP segments.
704 @param Nbuf Buffer that contains received TCP segment without IP header.
705 @param Src Source address of the segment, or the peer's IP address.
706 @param Dst Destination address of the segment, or the local end's IP
709 @retval 0 Segment is processed successfully. It is either accepted or
710 discarded. But no connection is reset by the segment.
711 @retval -1 A connection is reset by the segment.
730 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
735 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
736 Len
= Nbuf
->TotalSize
- (Head
->HeadLen
<< 2);
738 if ((Head
->HeadLen
< 5) || (Len
< 0) ||
739 TcpChecksum (Nbuf
, NetPseudoHeadChecksum (Src
, Dst
, 6, 0))) {
741 TCP4_DEBUG_TRACE (("TcpInput: received an mal-formated packet\n"));
745 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)) {
749 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_FIN
)) {
758 (BOOLEAN
) TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)
761 if ((Tcb
== NULL
) || (Tcb
->State
== TCP_CLOSED
)) {
762 TCP4_DEBUG_TRACE (("TcpInput: send reset because no TCB find\n"));
768 Seg
= TcpFormatNetbuf (Tcb
, Nbuf
);
771 // RFC1122 recommended reaction to illegal option
772 // (in fact, an illegal option length) is reset.
774 if (TcpParseOption (Nbuf
->Tcp
, &Option
) == -1) {
775 TCP4_DEBUG_ERROR (("TcpInput: reset the peer because"
776 " of mal-format option for Tcb %x\n", Tcb
));
782 // From now on, the segment is headless
784 NetbufTrim (Nbuf
, (Head
->HeadLen
<< 2), NET_BUF_HEAD
);
788 // TODO: add fast path process here
792 // Process the segment in LISTEN state.
794 if (Tcb
->State
== TCP_LISTEN
) {
796 // First step: Check RST
798 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
799 TCP4_DEBUG_WARN (("TcpInput: discard a reset segment "
800 "for TCB %x in listening\n", Tcb
));
806 // Second step: Check ACK.
807 // Any ACK sent to TCP in LISTEN is reseted.
809 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
810 TCP4_DEBUG_WARN (("TcpInput: send reset because of"
811 " segment with ACK for TCB %x in listening\n", Tcb
));
817 // Third step: Check SYN
819 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
821 // create a child TCB to handle the data
825 Tcb
= TcpCloneTcb (Parent
);
827 TCP4_DEBUG_ERROR (("TcpInput: discard a segment because"
828 "failed to clone a child for TCB%x\n", Tcb
));
833 TCP4_DEBUG_TRACE (("TcpInput: create a child for TCB %x"
834 " in listening\n", Tcb
));
837 // init the TCB structure
839 Tcb
->LocalEnd
.Ip
= Dst
;
840 Tcb
->LocalEnd
.Port
= Head
->DstPort
;
841 Tcb
->RemoteEnd
.Ip
= Src
;
842 Tcb
->RemoteEnd
.Port
= Head
->SrcPort
;
844 TcpInitTcbLocal (Tcb
);
845 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
847 TcpSetState (Tcb
, TCP_SYN_RCVD
);
848 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
849 TcpTrimInWnd (Tcb
, Nbuf
);
856 } else if (Tcb
->State
== TCP_SYN_SENT
) {
858 // First step: Check ACK bit
860 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
) && (Seg
->Ack
!= Tcb
->Iss
+ 1)) {
862 TCP4_DEBUG_WARN (("TcpInput: send reset because of "
863 "wrong ACK received for TCB %x in SYN_SENT\n", Tcb
));
869 // Second step: Check RST bit
871 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
873 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
875 TCP4_DEBUG_WARN (("TcpInput: connection reset by"
876 " peer for TCB%x in SYN_SENT\n", Tcb
));
878 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
879 goto DROP_CONNECTION
;
882 TCP4_DEBUG_WARN (("TcpInput: discard a reset segment "
883 "because of no ACK for TCB%x in SYN_SENT\n", Tcb
));
890 // Third step: Check security and precedence. Skipped
894 // Fourth step: Check SYN. Pay attention to sitimulatous open
896 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
898 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
900 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
902 Tcb
->SndUna
= Seg
->Ack
;
905 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
907 if (TCP_SEQ_GT (Tcb
->SndUna
, Tcb
->Iss
)) {
909 TcpSetState (Tcb
, TCP_ESTABLISHED
);
911 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
912 TcpDeliverData (Tcb
);
914 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
915 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
917 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
918 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
921 TcpTrimInWnd (Tcb
, Nbuf
);
923 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
925 TCP4_DEBUG_TRACE (("TcpInput: connection established"
926 " for TCB %x in SYN_SENT\n", Tcb
));
931 // Received a SYN segment without ACK, simultanous open.
933 TcpSetState (Tcb
, TCP_SYN_RCVD
);
935 ASSERT (Tcb
->SndNxt
== Tcb
->Iss
+ 1);
936 TcpAdjustSndQue (Tcb
, Tcb
->SndNxt
);
938 TcpTrimInWnd (Tcb
, Nbuf
);
940 TCP4_DEBUG_WARN (("TcpInput: simultanous open "
941 "for TCB %x in SYN_SENT\n", Tcb
));
951 // Process segment in SYN_RCVD or TCP_CONNECTED states
955 // First step: Check whether SEG.SEQ is acceptable
957 if (!TcpSeqAcceptable (Tcb
, Seg
)) {
958 TCP4_DEBUG_WARN (("TcpInput: sequence acceptance"
959 " test failed for segment of TCB %x\n", Tcb
));
961 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
968 if ((TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
)) &&
969 (Tcb
->RcvWl2
== Seg
->End
) &&
970 !TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
| TCP_FLG_FIN
)) {
972 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
976 // Second step: Check the RST
978 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
980 TCP4_DEBUG_WARN (("TcpInput: connection reset for TCB %x\n", Tcb
));
982 if (Tcb
->State
== TCP_SYN_RCVD
) {
984 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_REFUSED
);
987 // This TCB comes from either a LISTEN TCB,
988 // or active open TCB with simultanous open.
989 // Do NOT signal user CONNECTION refused
990 // if it comes from a LISTEN TCB.
992 } else if ((Tcb
->State
== TCP_ESTABLISHED
) ||
993 (Tcb
->State
== TCP_FIN_WAIT_1
) ||
994 (Tcb
->State
== TCP_FIN_WAIT_2
) ||
995 (Tcb
->State
== TCP_CLOSE_WAIT
)
998 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1002 // TODO: set socket error to CLOSED
1006 goto DROP_CONNECTION
;
1010 // Trim the data and flags.
1012 TcpTrimInWnd (Tcb
, Nbuf
);
1015 // Third step: Check security and precedence, Ignored
1019 // Fourth step: Check the SYN bit.
1021 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1023 TCP4_DEBUG_WARN (("TcpInput: connection reset "
1024 "because received extra SYN for TCB %x\n", Tcb
));
1026 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
1027 goto RESET_THEN_DROP
;
1031 // Fifth step: Check the ACK
1033 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
1034 TCP4_DEBUG_WARN (("TcpInput: segment discard because"
1035 " of no ACK for connected TCB %x\n", Tcb
));
1041 if (Tcb
->State
== TCP_SYN_RCVD
) {
1043 if (TCP_SEQ_LT (Tcb
->SndUna
, Seg
->Ack
) &&
1044 TCP_SEQ_LEQ (Seg
->Ack
, Tcb
->SndNxt
)) {
1046 Tcb
->SndWnd
= Seg
->Wnd
;
1047 Tcb
->SndWndMax
= NET_MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1048 Tcb
->SndWl1
= Seg
->Seq
;
1049 Tcb
->SndWl2
= Seg
->Ack
;
1050 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1052 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1053 TcpDeliverData (Tcb
);
1055 TCP4_DEBUG_TRACE (("TcpInput: connection established "
1056 " for TCB %x in SYN_RCVD\n", Tcb
));
1059 // Continue the process as ESTABLISHED state
1062 TCP4_DEBUG_WARN (("TcpInput: send reset because of"
1063 " wrong ACK for TCB %x in SYN_RCVD\n", Tcb
));
1069 if (TCP_SEQ_LT (Seg
->Ack
, Tcb
->SndUna
)) {
1071 TCP4_DEBUG_WARN (("TcpInput: ignore the out-of-data"
1072 " ACK for connected TCB %x\n", Tcb
));
1076 } else if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndNxt
)) {
1078 TCP4_DEBUG_WARN (("TcpInput: discard segment for "
1079 "future ACK for connected TCB %x\n", Tcb
));
1086 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1088 if (TCP_FLG_ON (Option
.Flag
, TCP_OPTION_RCVD_TS
)) {
1090 // update TsRecent as specified in page 16 RFC1323.
1091 // RcvWl2 equals to the variable "LastAckSent"
1094 if (TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
) &&
1095 TCP_SEQ_LT (Tcb
->RcvWl2
, Seg
->End
)) {
1097 Tcb
->TsRecent
= Option
.TSVal
;
1098 Tcb
->TsRecentAge
= mTcpTick
;
1101 TcpComputeRtt (Tcb
, TCP_SUB_TIME (mTcpTick
, Option
.TSEcr
));
1103 } else if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
1105 ASSERT (Tcb
->CongestState
== TCP_CONGEST_OPEN
);
1107 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1108 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1111 if (Seg
->Ack
== Tcb
->SndNxt
) {
1113 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1116 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
1120 // Count duplicate acks.
1122 if ((Seg
->Ack
== Tcb
->SndUna
) &&
1123 (Tcb
->SndUna
!= Tcb
->SndNxt
) &&
1124 (Seg
->Wnd
== Tcb
->SndWnd
) &&
1134 // Congestion avoidance, fast recovery and fast retransmission.
1136 if (((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && (Tcb
->DupAck
< 3)) ||
1137 (Tcb
->CongestState
== TCP_CONGEST_LOSS
)) {
1139 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1141 if (Tcb
->CWnd
< Tcb
->Ssthresh
) {
1143 Tcb
->CWnd
+= Tcb
->SndMss
;
1146 Tcb
->CWnd
+= NET_MAX (Tcb
->SndMss
* Tcb
->SndMss
/ Tcb
->CWnd
, 1);
1149 Tcb
->CWnd
= NET_MIN (Tcb
->CWnd
, TCP_MAX_WIN
<< Tcb
->SndWndScale
);
1152 if (Tcb
->CongestState
== TCP_CONGEST_LOSS
) {
1153 TcpFastLossRecover (Tcb
, Seg
);
1157 TcpFastRecover (Tcb
, Seg
);
1160 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1162 TcpAdjustSndQue (Tcb
, Seg
->Ack
);
1163 Tcb
->SndUna
= Seg
->Ack
;
1165 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
1166 (TCP_SEQ_LT (Tcb
->SndUp
, Seg
->Ack
))) {
1168 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
1173 // Update window info
1175 if (TCP_SEQ_LT (Tcb
->SndWl1
, Seg
->Seq
) ||
1176 ((Tcb
->SndWl1
== Seg
->Seq
) && TCP_SEQ_LEQ (Tcb
->SndWl2
, Seg
->Ack
))) {
1178 Right
= Seg
->Ack
+ Seg
->Wnd
;
1180 if (TCP_SEQ_LT (Right
, Tcb
->SndWl2
+ Tcb
->SndWnd
)) {
1182 if ((Tcb
->SndWl1
== Seg
->Seq
) &&
1183 (Tcb
->SndWl2
== Seg
->Ack
) &&
1189 TCP4_DEBUG_WARN (("TcpInput: peer shrinks the"
1190 " window for connected TCB %x\n", Tcb
));
1192 if ((Tcb
->CongestState
== TCP_CONGEST_RECOVER
) &&
1193 (TCP_SEQ_LT (Right
, Tcb
->Recover
))) {
1195 Tcb
->Recover
= Right
;
1198 if ((Tcb
->CongestState
== TCP_CONGEST_LOSS
) &&
1199 (TCP_SEQ_LT (Right
, Tcb
->LossRecover
))) {
1201 Tcb
->LossRecover
= Right
;
1204 if (TCP_SEQ_LT (Right
, Tcb
->SndNxt
)) {
1206 Tcb
->SndNxt
= Right
;
1208 if (Right
== Tcb
->SndUna
) {
1210 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1211 TcpSetProbeTimer (Tcb
);
1216 Tcb
->SndWnd
= Seg
->Wnd
;
1217 Tcb
->SndWndMax
= NET_MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1218 Tcb
->SndWl1
= Seg
->Seq
;
1219 Tcb
->SndWl2
= Seg
->Ack
;
1224 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
) &&
1225 (Tcb
->SndUna
== Tcb
->SndNxt
)) {
1227 TCP4_DEBUG_TRACE (("TcpInput: local FIN is ACKed by"
1228 " peer for connected TCB %x\n", Tcb
));
1230 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
);
1234 // Transit the state if proper.
1236 switch (Tcb
->State
) {
1237 case TCP_FIN_WAIT_1
:
1239 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1241 TcpSetState (Tcb
, TCP_FIN_WAIT_2
);
1243 TcpClearAllTimer (Tcb
);
1244 TcpSetTimer (Tcb
, TCP_TIMER_FINWAIT2
, Tcb
->FinWait2Timeout
);
1247 case TCP_FIN_WAIT_2
:
1251 case TCP_CLOSE_WAIT
:
1256 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1258 TcpSetState (Tcb
, TCP_TIME_WAIT
);
1260 TcpClearAllTimer (Tcb
);
1262 if (Tcb
->TimeWaitTimeout
!= 0) {
1264 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1267 TCP4_DEBUG_WARN (("Connection closed immediately "
1268 "because app disables TIME_WAIT timer for %x\n", Tcb
));
1277 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1279 TcpSetState (Tcb
, TCP_CLOSED
);
1288 if (Tcb
->TimeWaitTimeout
!= 0) {
1290 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1293 TCP4_DEBUG_WARN (("Connection closed immediately "
1294 "because app disables TIME_WAIT timer for %x\n", Tcb
));
1302 // Sixth step: Check the URG bit.update the Urg point
1303 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1308 TcpSetKeepaliveTimer (Tcb
);
1310 if (TCP_TIMER_ON (Tcb
->EnabledTimer
, TCP_TIMER_PROBE
)) {
1312 TcpClearTimer (Tcb
, TCP_TIMER_PROBE
);
1315 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
) &&
1316 !TCP_FIN_RCVD (Tcb
->State
)) {
1318 TCP4_DEBUG_TRACE (("TcpInput: received urgent data "
1319 "from peer for connected TCB %x\n", Tcb
));
1321 Urg
= Seg
->Seq
+ Seg
->Urg
;
1323 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
1324 TCP_SEQ_GT (Urg
, Tcb
->RcvUp
)) {
1330 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
);
1335 // Seventh step: Process the segment data
1337 if (Seg
->End
!= Seg
->Seq
) {
1339 if (TCP_FIN_RCVD (Tcb
->State
)) {
1341 TCP4_DEBUG_WARN (("TcpInput: connection reset because"
1342 " data is lost for connected TCB %x\n", Tcb
));
1344 goto RESET_THEN_DROP
;
1347 if (TCP_LOCAL_CLOSED (Tcb
->State
) && (Nbuf
->TotalSize
!= 0)) {
1348 TCP4_DEBUG_WARN (("TcpInput: connection reset because"
1349 " data is lost for connected TCB %x\n", Tcb
));
1351 goto RESET_THEN_DROP
;
1354 TcpQueueData (Tcb
, Nbuf
);
1355 if (TcpDeliverData (Tcb
) == -1) {
1356 goto RESET_THEN_DROP
;
1359 if (!NetListIsEmpty (&Tcb
->RcvQue
)) {
1360 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1365 // Eighth step: check the FIN.
1366 // This step is moved to TcpDeliverData. FIN will be
1367 // processed in sequence there. Check the comments in
1368 // the beginning of the file header for information.
1372 // Tcb is a new child of the listening Parent,
1376 Tcb
->Parent
= Parent
;
1380 if ((Tcb
->State
!= TCP_CLOSED
) &&
1381 (!TcpToSendData (Tcb
, 0)) &&
1382 (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || Nbuf
->TotalSize
)) {
1391 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1394 ASSERT (Tcb
&& Tcb
->Sk
);
1403 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1408 // Tcb is a child of Parent, and it doesn't survive
1410 TCP4_DEBUG_WARN (("Tcp4Input: Discard a packet\n"));
1413 if (Parent
&& Tcb
) {
1424 Process the received ICMP error messages for TCP.
1426 @param Nbuf Buffer that contains part of the TCP segment without IP header
1427 truncated from the ICMP error packet.
1428 @param IcmpErr The ICMP error code interpreted from ICMP error packet.
1429 @param Src Source address of the ICMP error message.
1430 @param Dst Destination address of the ICMP error message.
1438 IN ICMP_ERROR IcmpErr
,
1446 EFI_STATUS IcmpErrStatus
;
1447 BOOLEAN IcmpErrIsHard
;
1448 BOOLEAN IcmpErrNotify
;
1450 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
1451 Tcb
= TcpLocateTcb (
1458 if (Tcb
== NULL
|| Tcb
->State
== TCP_CLOSED
) {
1464 // Validate the sequence number.
1466 Seq
= NTOHL (Head
->Seq
);
1467 if (!(TCP_SEQ_LEQ (Tcb
->SndUna
, Seq
) && TCP_SEQ_LT (Seq
, Tcb
->SndNxt
))) {
1472 IcmpErrStatus
= IpIoGetIcmpErrStatus (IcmpErr
, &IcmpErrIsHard
, &IcmpErrNotify
);
1474 if (IcmpErrNotify
) {
1476 SOCK_ERROR (Tcb
->Sk
, IcmpErrStatus
);
1479 if (IcmpErrIsHard
) {