]>
git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c
2 TCP input process routines.
4 Copyright (c) 2005 - 2007, Intel Corporation<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php<BR>
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 Check whether the sequence number of the incoming segment is acceptable.
22 @param Tcb Pointer to the TCP_CB of this TCP instance.
23 @param Seg Pointer to the incoming segment.
25 @retval 1 The sequence number is acceptable.
26 @retval 0 The sequence number is not acceptable.
35 return (TCP_SEQ_LEQ (Tcb
->RcvWl2
, Seg
->End
) &&
36 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
+ Tcb
->RcvWnd
));
41 NewReno fast recovery, RFC3782.
43 @param Tcb Pointer to the TCP_CB of this TCP instance.
44 @param Seg Segment that triggers the fast recovery.
57 // Step 1: Three duplicate ACKs and not in fast recovery
59 if (Tcb
->CongestState
!= TCP_CONGEST_RECOVER
) {
62 // Step 1A: Invoking fast retransmission.
64 FlightSize
= TCP_SUB_SEQ (Tcb
->SndNxt
, Tcb
->SndUna
);
66 Tcb
->Ssthresh
= MAX (FlightSize
>> 1, (UINT32
) (2 * Tcb
->SndMss
));
67 Tcb
->Recover
= Tcb
->SndNxt
;
69 Tcb
->CongestState
= TCP_CONGEST_RECOVER
;
70 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
73 // Step 2: Entering fast retransmission
75 TcpRetransmit (Tcb
, Tcb
->SndUna
);
76 Tcb
->CWnd
= Tcb
->Ssthresh
+ 3 * Tcb
->SndMss
;
78 DEBUG ((EFI_D_INFO
, "TcpFastRecover: enter fast retransmission"
79 " for TCB %p, recover point is %d\n", Tcb
, Tcb
->Recover
));
84 // During fast recovery, execute Step 3, 4, 5 of RFC3782
86 if (Seg
->Ack
== Tcb
->SndUna
) {
89 // Step 3: Fast Recovery,
90 // If this is a duplicated ACK, increse Cwnd by SMSS.
93 // Step 4 is skipped here only to be executed later
96 Tcb
->CWnd
+= Tcb
->SndMss
;
97 DEBUG ((EFI_D_INFO
, "TcpFastRecover: received another"
98 " duplicated ACK (%d) for TCB %p\n", Seg
->Ack
, Tcb
));
103 // New data is ACKed, check whether it is a
104 // full ACK or partial ACK
106 if (TCP_SEQ_GEQ (Seg
->Ack
, Tcb
->Recover
)) {
109 // Step 5 - Full ACK:
110 // deflate the congestion window, and exit fast recovery
112 FlightSize
= TCP_SUB_SEQ (Tcb
->SndNxt
, Tcb
->SndUna
);
114 Tcb
->CWnd
= MIN (Tcb
->Ssthresh
, FlightSize
+ Tcb
->SndMss
);
116 Tcb
->CongestState
= TCP_CONGEST_OPEN
;
117 DEBUG ((EFI_D_INFO
, "TcpFastRecover: received a full ACK(%d)"
118 " for TCB %p, exit fast recovery\n", Seg
->Ack
, Tcb
));
123 // Step 5 - Partial ACK:
124 // fast retransmit the first unacknowledge field
125 // , then deflate the CWnd
127 TcpRetransmit (Tcb
, Seg
->Ack
);
128 Acked
= TCP_SUB_SEQ (Seg
->Ack
, Tcb
->SndUna
);
131 // Deflate the CWnd by the amount of new data
132 // ACKed by SEG.ACK. If more than one SMSS data
133 // is ACKed, add back SMSS byte to CWnd after
135 if (Acked
>= Tcb
->SndMss
) {
136 Acked
-= Tcb
->SndMss
;
142 DEBUG ((EFI_D_INFO
, "TcpFastRecover: received a partial"
143 " ACK(%d) for TCB %p\n", Seg
->Ack
, Tcb
));
151 NewReno fast loss recovery, RFC3792.
153 @param Tcb Pointer to the TCP_CB of this TCP instance.
154 @param Seg Segment that triggers the fast loss recovery.
163 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
166 // New data is ACKed, check whether it is a
167 // full ACK or partial ACK
169 if (TCP_SEQ_GEQ (Seg
->Ack
, Tcb
->LossRecover
)) {
172 // Full ACK: exit the loss recovery.
175 Tcb
->CongestState
= TCP_CONGEST_OPEN
;
177 DEBUG ((EFI_D_INFO
, "TcpFastLossRecover: received a "
178 "full ACK(%d) for TCB %p\n", Seg
->Ack
, Tcb
));
184 // fast retransmit the first unacknowledge field.
186 TcpRetransmit (Tcb
, Seg
->Ack
);
187 DEBUG ((EFI_D_INFO
, "TcpFastLossRecover: received a "
188 "partial ACK(%d) for TCB %p\n", Seg
->Ack
, Tcb
));
195 Compute the RTT as specified in RFC2988.
197 @param Tcb Pointer to the TCP_CB of this TCP instance.
198 @param Measure Currently measured RTT in heart beats.
210 // Step 2.3: Compute the RTO for subsequent RTT measurement.
212 if (Tcb
->SRtt
!= 0) {
214 Var
= Tcb
->SRtt
- (Measure
<< TCP_RTT_SHIFT
);
220 Tcb
->RttVar
= (3 * Tcb
->RttVar
+ Var
) >> 2;
221 Tcb
->SRtt
= 7 * (Tcb
->SRtt
>> 3) + Measure
;
225 // Step 2.2: compute the first RTT measure
227 Tcb
->SRtt
= Measure
<< TCP_RTT_SHIFT
;
228 Tcb
->RttVar
= Measure
<< (TCP_RTT_SHIFT
- 1);
231 Tcb
->Rto
= (Tcb
->SRtt
+ MAX (8, 4 * Tcb
->RttVar
)) >> TCP_RTT_SHIFT
;
234 // Step 2.4: Limit the RTO to at least 1 second
235 // Step 2.5: Limit the RTO to a maxium value that
236 // is at least 60 second
238 if (Tcb
->Rto
< TCP_RTO_MIN
) {
239 Tcb
->Rto
= TCP_RTO_MIN
;
241 } else if (Tcb
->Rto
> TCP_RTO_MAX
) {
242 Tcb
->Rto
= TCP_RTO_MAX
;
246 DEBUG ((EFI_D_INFO
, "TcpComputeRtt: new RTT for TCB %p"
247 " computed SRTT: %d RTTVAR: %d RTO: %d\n",
248 Tcb
, Tcb
->SRtt
, Tcb
->RttVar
, Tcb
->Rto
));
254 Trim the data, SYN and FIN to fit into the window defined by Left and Right.
256 @param Nbuf Buffer that contains received TCP segment without IP header.
257 @param Left The sequence number of the window's left edge.
258 @param Right The sequence number of the window's right edge.
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
);
288 // Adjust the buffer header
290 if (TCP_SEQ_LT (Seg
->Seq
, Left
)) {
292 Drop
= TCP_SUB_SEQ (Left
, Seg
->Seq
);
293 Urg
= Seg
->Seq
+ Seg
->Urg
;
296 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
297 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_SYN
);
302 // Adjust the urgent point
304 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
)) {
306 if (TCP_SEQ_LT (Urg
, Seg
->Seq
)) {
308 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_URG
);
310 Seg
->Urg
= (UINT16
) TCP_SUB_SEQ (Urg
, Seg
->Seq
);
315 NetbufTrim (Nbuf
, Drop
, NET_BUF_HEAD
);
320 // Adjust the buffer tail
322 if (TCP_SEQ_GT (Seg
->End
, Right
)) {
324 Drop
= TCP_SUB_SEQ (Seg
->End
, Right
);
327 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
328 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_FIN
);
333 NetbufTrim (Nbuf
, Drop
, NET_BUF_TAIL
);
337 ASSERT (TcpVerifySegment (Nbuf
) != 0);
342 Trim off the data outside the tcb's receive window.
344 @param Tcb Pointer to the TCP_CB of this TCP instance.
345 @param Nbuf Pointer to the NET_BUF containing the received tcp segment.
354 TcpTrimSegment (Nbuf
, Tcb
->RcvNxt
, Tcb
->RcvWl2
+ Tcb
->RcvWnd
);
359 Process the data and FIN flag, check whether to deliver
360 data to the socket layer.
362 @param Tcb Pointer to the TCP_CB of this TCP instance.
364 @retval 0 No error occurred to deliver data.
365 @retval -1 Error condition occurred. Proper response is to reset the
380 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
383 // make sure there is some data queued,
384 // and TCP is in a proper state
386 if (IsListEmpty (&Tcb
->RcvQue
) || !TCP_CONNECTED (Tcb
->State
)) {
392 // Deliver data to the socket layer
394 Entry
= Tcb
->RcvQue
.ForwardLink
;
397 while (Entry
!= &Tcb
->RcvQue
) {
398 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
399 Seg
= TCPSEG_NETBUF (Nbuf
);
401 ASSERT (TcpVerifySegment (Nbuf
) != 0);
402 ASSERT (Nbuf
->Tcp
== NULL
);
404 if (TCP_SEQ_GT (Seg
->Seq
, Seq
)) {
408 Entry
= Entry
->ForwardLink
;
412 RemoveEntryList (&Nbuf
->List
);
415 // RFC793 Eighth step: process FIN in sequence
417 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
420 // The peer sends to us junky data after FIN,
421 // reset the connection.
423 if (!IsListEmpty (&Tcb
->RcvQue
)) {
424 DEBUG ((EFI_D_ERROR
, "TcpDeliverData: data received after"
425 " FIN from peer of TCB %p, reset connection\n", Tcb
));
431 DEBUG ((EFI_D_INFO
, "TcpDeliverData: processing FIN "
432 "from peer of TCB %p\n", Tcb
));
434 switch (Tcb
->State
) {
436 case TCP_ESTABLISHED
:
438 TcpSetState (Tcb
, TCP_CLOSE_WAIT
);
443 if (!TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
445 TcpSetState (Tcb
, TCP_CLOSING
);
454 TcpSetState (Tcb
, TCP_TIME_WAIT
);
455 TcpClearAllTimer (Tcb
);
457 if (Tcb
->TimeWaitTimeout
!= 0) {
459 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
462 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
463 "because app disables TIME_WAIT timer for %p\n", Tcb
));
475 // The peer sends to us junk FIN byte. Discard
476 // the buffer then reset the connection
485 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
491 // Don't delay the ack if PUSH flag is on.
493 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_PSH
)) {
495 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
498 if (Nbuf
->TotalSize
) {
501 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
502 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvUp
)) {
504 if (TCP_SEQ_LEQ (Seg
->End
, Tcb
->RcvUp
)) {
505 Urgent
= Nbuf
->TotalSize
;
507 Urgent
= TCP_SUB_SEQ (Tcb
->RcvUp
, Seg
->Seq
) + 1;
511 SockDataRcvd (Tcb
->Sk
, Nbuf
, Urgent
);
514 if (TCP_FIN_RCVD (Tcb
->State
)) {
516 SockNoMoreData (Tcb
->Sk
);
527 Store the data into the reassemble queue.
529 @param Tcb Pointer to the TCP_CB of this TCP instance.
530 @param Nbuf Pointer to the buffer containing the data to be queued.
545 ASSERT ((Tcb
!= NULL
) && (Nbuf
!= NULL
) && (Nbuf
->Tcp
== NULL
));
549 Seg
= TCPSEG_NETBUF (Nbuf
);
553 // Fast path to process normal case. That is,
554 // no out-of-order segments are received.
556 if (IsListEmpty (Head
)) {
558 InsertTailList (Head
, &Nbuf
->List
);
563 // Find the point to insert the buffer
565 for (Prev
= Head
, Cur
= Head
->ForwardLink
;
567 Prev
= Cur
, Cur
= Cur
->ForwardLink
) {
569 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
571 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
)) {
577 // Check whether the current segment overlaps with the
581 Node
= NET_LIST_USER_STRUCT (Prev
, NET_BUF
, List
);
583 if (TCP_SEQ_LT (Seg
->Seq
, TCPSEG_NETBUF (Node
)->End
)) {
585 if (TCP_SEQ_LEQ (Seg
->End
, TCPSEG_NETBUF (Node
)->End
)) {
591 TcpTrimSegment (Nbuf
, TCPSEG_NETBUF (Node
)->End
, Seg
->End
);
595 InsertHeadList (Prev
, &Nbuf
->List
);
597 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
600 // Check the segments after the insert point.
602 while (Cur
!= Head
) {
603 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
605 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->End
, Seg
->End
)) {
607 Cur
= Cur
->ForwardLink
;
609 RemoveEntryList (&Node
->List
);
614 if (TCP_SEQ_LT (TCPSEG_NETBUF (Node
)->Seq
, Seg
->End
)) {
616 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node
)->Seq
, Seg
->Seq
)) {
618 RemoveEntryList (&Nbuf
->List
);
623 TcpTrimSegment (Nbuf
, Seg
->Seq
, TCPSEG_NETBUF (Node
)->Seq
);
627 Cur
= Cur
->ForwardLink
;
633 Ajust the send queue or the retransmit queue.
635 @param Tcb Pointer to the TCP_CB of this TCP instance.
636 @param Ack The acknowledge seuqence number of the received segment.
651 Cur
= Head
->ForwardLink
;
653 while (Cur
!= Head
) {
654 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
655 Seg
= TCPSEG_NETBUF (Node
);
657 if (TCP_SEQ_GEQ (Seg
->Seq
, Ack
)) {
662 // Remove completely ACKed segments
664 if (TCP_SEQ_LEQ (Seg
->End
, Ack
)) {
665 Cur
= Cur
->ForwardLink
;
667 RemoveEntryList (&Node
->List
);
672 TcpTrimSegment (Node
, Ack
, Seg
->End
);
679 Process the received TCP segments.
681 @param Nbuf Buffer that contains received TCP segment without IP header.
682 @param Src Source address of the segment, or the peer's IP address.
683 @param Dst Destination address of the segment, or the local end's IP
686 @retval 0 Segment is processed successfully. It is either accepted or
687 discarded. But no connection is reset by the segment.
688 @retval -1 A connection is reset by the segment.
707 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
712 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
713 Len
= Nbuf
->TotalSize
- (Head
->HeadLen
<< 2);
715 if ((Head
->HeadLen
< 5) || (Len
< 0) ||
716 (TcpChecksum (Nbuf
, NetPseudoHeadChecksum (Src
, Dst
, 6, 0)) != 0)) {
718 DEBUG ((EFI_D_INFO
, "TcpInput: received an mal-formated packet\n"));
722 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)) {
726 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_FIN
)) {
735 (BOOLEAN
) TCP_FLG_ON (Head
->Flag
, TCP_FLG_SYN
)
738 if ((Tcb
== NULL
) || (Tcb
->State
== TCP_CLOSED
)) {
739 DEBUG ((EFI_D_INFO
, "TcpInput: send reset because no TCB find\n"));
745 Seg
= TcpFormatNetbuf (Tcb
, Nbuf
);
748 // RFC1122 recommended reaction to illegal option
749 // (in fact, an illegal option length) is reset.
751 if (TcpParseOption (Nbuf
->Tcp
, &Option
) == -1) {
752 DEBUG ((EFI_D_ERROR
, "TcpInput: reset the peer because"
753 " of mal-format option for Tcb %p\n", Tcb
));
759 // From now on, the segment is headless
761 NetbufTrim (Nbuf
, (Head
->HeadLen
<< 2), NET_BUF_HEAD
);
765 // Process the segment in LISTEN state.
767 if (Tcb
->State
== TCP_LISTEN
) {
769 // First step: Check RST
771 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
772 DEBUG ((EFI_D_WARN
, "TcpInput: discard a reset segment "
773 "for TCB %p in listening\n", Tcb
));
779 // Second step: Check ACK.
780 // Any ACK sent to TCP in LISTEN is reseted.
782 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
783 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of"
784 " segment with ACK for TCB %p in listening\n", Tcb
));
790 // Third step: Check SYN
792 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
794 // create a child TCB to handle the data
798 Tcb
= TcpCloneTcb (Parent
);
800 DEBUG ((EFI_D_ERROR
, "TcpInput: discard a segment because"
801 "failed to clone a child for TCB%x\n", Tcb
));
806 DEBUG ((EFI_D_INFO
, "TcpInput: create a child for TCB %p"
807 " in listening\n", Tcb
));
810 // init the TCB structure
812 Tcb
->LocalEnd
.Ip
= Dst
;
813 Tcb
->LocalEnd
.Port
= Head
->DstPort
;
814 Tcb
->RemoteEnd
.Ip
= Src
;
815 Tcb
->RemoteEnd
.Port
= Head
->SrcPort
;
817 TcpInitTcbLocal (Tcb
);
818 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
820 TcpSetState (Tcb
, TCP_SYN_RCVD
);
821 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
822 TcpTrimInWnd (Tcb
, Nbuf
);
829 } else if (Tcb
->State
== TCP_SYN_SENT
) {
831 // First step: Check ACK bit
833 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
) && (Seg
->Ack
!= Tcb
->Iss
+ 1)) {
835 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of "
836 "wrong ACK received for TCB %p in SYN_SENT\n", Tcb
));
842 // Second step: Check RST bit
844 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
846 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
848 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset by"
849 " peer for TCB %p in SYN_SENT\n", Tcb
));
851 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
852 goto DROP_CONNECTION
;
855 DEBUG ((EFI_D_WARN
, "TcpInput: discard a reset segment "
856 "because of no ACK for TCB %p in SYN_SENT\n", Tcb
));
863 // Third step: Check security and precedence. Skipped
867 // Fourth step: Check SYN. Pay attention to sitimulatous open
869 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
871 TcpInitTcbPeer (Tcb
, Seg
, &Option
);
873 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
875 Tcb
->SndUna
= Seg
->Ack
;
878 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
880 if (TCP_SEQ_GT (Tcb
->SndUna
, Tcb
->Iss
)) {
882 TcpSetState (Tcb
, TCP_ESTABLISHED
);
884 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
885 TcpDeliverData (Tcb
);
887 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
888 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
890 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
891 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
894 TcpTrimInWnd (Tcb
, Nbuf
);
896 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
898 DEBUG ((EFI_D_INFO
, "TcpInput: connection established"
899 " for TCB %p in SYN_SENT\n", Tcb
));
904 // Received a SYN segment without ACK, simultanous open.
906 TcpSetState (Tcb
, TCP_SYN_RCVD
);
908 ASSERT (Tcb
->SndNxt
== Tcb
->Iss
+ 1);
909 TcpAdjustSndQue (Tcb
, Tcb
->SndNxt
);
911 TcpTrimInWnd (Tcb
, Nbuf
);
913 DEBUG ((EFI_D_WARN
, "TcpInput: simultanous open "
914 "for TCB %p in SYN_SENT\n", Tcb
));
924 // Process segment in SYN_RCVD or TCP_CONNECTED states
928 // First step: Check whether SEG.SEQ is acceptable
930 if (TcpSeqAcceptable (Tcb
, Seg
) == 0) {
931 DEBUG ((EFI_D_WARN
, "TcpInput: sequence acceptance"
932 " test failed for segment of TCB %p\n", Tcb
));
934 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
941 if ((TCP_SEQ_LT (Seg
->Seq
, Tcb
->RcvWl2
)) &&
942 (Tcb
->RcvWl2
== Seg
->End
) &&
943 !TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
| TCP_FLG_FIN
)) {
945 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
949 // Second step: Check the RST
951 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_RST
)) {
953 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset for TCB %p\n", Tcb
));
955 if (Tcb
->State
== TCP_SYN_RCVD
) {
957 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_REFUSED
);
960 // This TCB comes from either a LISTEN TCB,
961 // or active open TCB with simultanous open.
962 // Do NOT signal user CONNECTION refused
963 // if it comes from a LISTEN TCB.
965 } else if ((Tcb
->State
== TCP_ESTABLISHED
) ||
966 (Tcb
->State
== TCP_FIN_WAIT_1
) ||
967 (Tcb
->State
== TCP_FIN_WAIT_2
) ||
968 (Tcb
->State
== TCP_CLOSE_WAIT
)) {
970 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
976 goto DROP_CONNECTION
;
980 // Trim the data and flags.
982 TcpTrimInWnd (Tcb
, Nbuf
);
985 // Third step: Check security and precedence, Ignored
989 // Fourth step: Check the SYN bit.
991 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
993 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset "
994 "because received extra SYN for TCB %p\n", Tcb
));
996 SOCK_ERROR (Tcb
->Sk
, EFI_CONNECTION_RESET
);
997 goto RESET_THEN_DROP
;
1001 // Fifth step: Check the ACK
1003 if (!TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
1004 DEBUG ((EFI_D_WARN
, "TcpInput: segment discard because"
1005 " of no ACK for connected TCB %p\n", Tcb
));
1011 if (Tcb
->State
== TCP_SYN_RCVD
) {
1013 if (TCP_SEQ_LT (Tcb
->SndUna
, Seg
->Ack
) &&
1014 TCP_SEQ_LEQ (Seg
->Ack
, Tcb
->SndNxt
)) {
1016 Tcb
->SndWnd
= Seg
->Wnd
;
1017 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1018 Tcb
->SndWl1
= Seg
->Seq
;
1019 Tcb
->SndWl2
= Seg
->Ack
;
1020 TcpSetState (Tcb
, TCP_ESTABLISHED
);
1022 TcpClearTimer (Tcb
, TCP_TIMER_CONNECT
);
1023 TcpDeliverData (Tcb
);
1025 DEBUG ((EFI_D_INFO
, "TcpInput: connection established "
1026 " for TCB %p in SYN_RCVD\n", Tcb
));
1029 // Continue the process as ESTABLISHED state
1032 DEBUG ((EFI_D_WARN
, "TcpInput: send reset because of"
1033 " wrong ACK for TCB %p in SYN_RCVD\n", Tcb
));
1039 if (TCP_SEQ_LT (Seg
->Ack
, Tcb
->SndUna
)) {
1041 DEBUG ((EFI_D_WARN
, "TcpInput: ignore the out-of-data"
1042 " ACK for connected TCB %p\n", Tcb
));
1046 } else if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndNxt
)) {
1048 DEBUG ((EFI_D_WARN
, "TcpInput: discard segment for "
1049 "future ACK for connected TCB %p\n", Tcb
));
1056 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1058 if (TCP_FLG_ON (Option
.Flag
, TCP_OPTION_RCVD_TS
)) {
1060 // update TsRecent as specified in page 16 RFC1323.
1061 // RcvWl2 equals to the variable "LastAckSent"
1064 if (TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->RcvWl2
) &&
1065 TCP_SEQ_LT (Tcb
->RcvWl2
, Seg
->End
)) {
1067 Tcb
->TsRecent
= Option
.TSVal
;
1068 Tcb
->TsRecentAge
= mTcpTick
;
1071 TcpComputeRtt (Tcb
, TCP_SUB_TIME (mTcpTick
, Option
.TSEcr
));
1073 } else if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
1075 ASSERT (Tcb
->CongestState
== TCP_CONGEST_OPEN
);
1077 TcpComputeRtt (Tcb
, Tcb
->RttMeasure
);
1078 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
1081 if (Seg
->Ack
== Tcb
->SndNxt
) {
1083 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1086 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
1090 // Count duplicate acks.
1092 if ((Seg
->Ack
== Tcb
->SndUna
) &&
1093 (Tcb
->SndUna
!= Tcb
->SndNxt
) &&
1094 (Seg
->Wnd
== Tcb
->SndWnd
) &&
1104 // Congestion avoidance, fast recovery and fast retransmission.
1106 if (((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && (Tcb
->DupAck
< 3)) ||
1107 (Tcb
->CongestState
== TCP_CONGEST_LOSS
)) {
1109 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1111 if (Tcb
->CWnd
< Tcb
->Ssthresh
) {
1113 Tcb
->CWnd
+= Tcb
->SndMss
;
1116 Tcb
->CWnd
+= MAX (Tcb
->SndMss
* Tcb
->SndMss
/ Tcb
->CWnd
, 1);
1119 Tcb
->CWnd
= MIN (Tcb
->CWnd
, TCP_MAX_WIN
<< Tcb
->SndWndScale
);
1122 if (Tcb
->CongestState
== TCP_CONGEST_LOSS
) {
1123 TcpFastLossRecover (Tcb
, Seg
);
1127 TcpFastRecover (Tcb
, Seg
);
1130 if (TCP_SEQ_GT (Seg
->Ack
, Tcb
->SndUna
)) {
1132 TcpAdjustSndQue (Tcb
, Seg
->Ack
);
1133 Tcb
->SndUna
= Seg
->Ack
;
1135 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
1136 TCP_SEQ_LT (Tcb
->SndUp
, Seg
->Ack
)) {
1138 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
1143 // Update window info
1145 if (TCP_SEQ_LT (Tcb
->SndWl1
, Seg
->Seq
) ||
1146 ((Tcb
->SndWl1
== Seg
->Seq
) && TCP_SEQ_LEQ (Tcb
->SndWl2
, Seg
->Ack
))) {
1148 Right
= Seg
->Ack
+ Seg
->Wnd
;
1150 if (TCP_SEQ_LT (Right
, Tcb
->SndWl2
+ Tcb
->SndWnd
)) {
1152 if ((Tcb
->SndWl1
== Seg
->Seq
) &&
1153 (Tcb
->SndWl2
== Seg
->Ack
) &&
1159 DEBUG ((EFI_D_WARN
, "TcpInput: peer shrinks the"
1160 " window for connected TCB %p\n", Tcb
));
1162 if ((Tcb
->CongestState
== TCP_CONGEST_RECOVER
) &&
1163 (TCP_SEQ_LT (Right
, Tcb
->Recover
))) {
1165 Tcb
->Recover
= Right
;
1168 if ((Tcb
->CongestState
== TCP_CONGEST_LOSS
) &&
1169 (TCP_SEQ_LT (Right
, Tcb
->LossRecover
))) {
1171 Tcb
->LossRecover
= Right
;
1174 if (TCP_SEQ_LT (Right
, Tcb
->SndNxt
)) {
1176 Tcb
->SndNxt
= Right
;
1178 if (Right
== Tcb
->SndUna
) {
1180 TcpClearTimer (Tcb
, TCP_TIMER_REXMIT
);
1181 TcpSetProbeTimer (Tcb
);
1186 Tcb
->SndWnd
= Seg
->Wnd
;
1187 Tcb
->SndWndMax
= MAX (Tcb
->SndWnd
, Tcb
->SndWndMax
);
1188 Tcb
->SndWl1
= Seg
->Seq
;
1189 Tcb
->SndWl2
= Seg
->Ack
;
1194 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
) &&
1195 (Tcb
->SndUna
== Tcb
->SndNxt
)) {
1197 DEBUG ((EFI_D_INFO
, "TcpInput: local FIN is ACKed by"
1198 " peer for connected TCB %p\n", Tcb
));
1200 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
);
1204 // Transit the state if proper.
1206 switch (Tcb
->State
) {
1207 case TCP_FIN_WAIT_1
:
1209 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1211 TcpSetState (Tcb
, TCP_FIN_WAIT_2
);
1213 TcpClearAllTimer (Tcb
);
1214 TcpSetTimer (Tcb
, TCP_TIMER_FINWAIT2
, Tcb
->FinWait2Timeout
);
1217 case TCP_FIN_WAIT_2
:
1221 case TCP_CLOSE_WAIT
:
1226 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1228 TcpSetState (Tcb
, TCP_TIME_WAIT
);
1230 TcpClearAllTimer (Tcb
);
1232 if (Tcb
->TimeWaitTimeout
!= 0) {
1234 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1237 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
1238 "because app disables TIME_WAIT timer for %p\n", Tcb
));
1247 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_ACKED
)) {
1249 TcpSetState (Tcb
, TCP_CLOSED
);
1258 if (Tcb
->TimeWaitTimeout
!= 0) {
1260 TcpSetTimer (Tcb
, TCP_TIMER_2MSL
, Tcb
->TimeWaitTimeout
);
1263 DEBUG ((EFI_D_WARN
, "Connection closed immediately "
1264 "because app disables TIME_WAIT timer for %p\n", Tcb
));
1272 // Sixth step: Check the URG bit.update the Urg point
1273 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1278 TcpSetKeepaliveTimer (Tcb
);
1280 if (TCP_TIMER_ON (Tcb
->EnabledTimer
, TCP_TIMER_PROBE
)) {
1282 TcpClearTimer (Tcb
, TCP_TIMER_PROBE
);
1285 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_URG
) &&
1286 !TCP_FIN_RCVD (Tcb
->State
)) {
1288 DEBUG ((EFI_D_INFO
, "TcpInput: received urgent data "
1289 "from peer for connected TCB %p\n", Tcb
));
1291 Urg
= Seg
->Seq
+ Seg
->Urg
;
1293 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
) &&
1294 TCP_SEQ_GT (Urg
, Tcb
->RcvUp
)) {
1300 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_URG
);
1305 // Seventh step: Process the segment data
1307 if (Seg
->End
!= Seg
->Seq
) {
1309 if (TCP_FIN_RCVD (Tcb
->State
)) {
1311 DEBUG ((EFI_D_WARN
, "TcpInput: connection reset because"
1312 " data is lost for connected TCB %p\n", Tcb
));
1314 goto RESET_THEN_DROP
;
1317 if (TCP_LOCAL_CLOSED (Tcb
->State
) && (Nbuf
->TotalSize
!= 0)) {
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 TcpQueueData (Tcb
, Nbuf
);
1325 if (TcpDeliverData (Tcb
) == -1) {
1326 goto RESET_THEN_DROP
;
1329 if (!IsListEmpty (&Tcb
->RcvQue
)) {
1330 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1335 // Eighth step: check the FIN.
1336 // This step is moved to TcpDeliverData. FIN will be
1337 // processed in sequence there. Check the comments in
1338 // the beginning of the file header for information.
1342 // Tcb is a new child of the listening Parent,
1345 if (Parent
!= NULL
) {
1346 Tcb
->Parent
= Parent
;
1350 if ((Tcb
->State
!= TCP_CLOSED
) &&
1351 (TcpToSendData (Tcb
, 0) == 0) &&
1352 (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || Nbuf
->TotalSize
)) {
1361 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1364 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
1373 TcpSendReset (Tcb
, Head
, Len
, Dst
, Src
);
1378 // Tcb is a child of Parent, and it doesn't survive
1380 DEBUG ((EFI_D_WARN
, "Tcp4Input: Discard a packet\n"));
1383 if ((Parent
!= NULL
) && (Tcb
!= NULL
)) {
1385 ASSERT (Tcb
->Sk
!= NULL
);
1394 Process the received ICMP error messages for TCP.
1396 @param Nbuf Buffer that contains part of the TCP segment without IP header
1397 truncated from the ICMP error packet.
1398 @param IcmpErr The ICMP error code interpreted from ICMP error packet.
1399 @param Src Source address of the ICMP error message.
1400 @param Dst Destination address of the ICMP error message.
1406 IN ICMP_ERROR IcmpErr
,
1414 EFI_STATUS IcmpErrStatus
;
1415 BOOLEAN IcmpErrIsHard
;
1416 BOOLEAN IcmpErrNotify
;
1418 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
1419 Tcb
= TcpLocateTcb (
1426 if (Tcb
== NULL
|| Tcb
->State
== TCP_CLOSED
) {
1432 // Validate the sequence number.
1434 Seq
= NTOHL (Head
->Seq
);
1435 if (!(TCP_SEQ_LEQ (Tcb
->SndUna
, Seq
) && TCP_SEQ_LT (Seq
, Tcb
->SndNxt
))) {
1440 IcmpErrStatus
= IpIoGetIcmpErrStatus (IcmpErr
, &IcmpErrIsHard
, &IcmpErrNotify
);
1442 if (IcmpErrNotify
) {
1444 SOCK_ERROR (Tcb
->Sk
, IcmpErrStatus
);
1447 if (IcmpErrIsHard
) {