]>
git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/TcpDxe/TcpOutput.c
2 TCP output process routines.
4 Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 UINT8 mTcpOutFlag
[] = {
21 TCP_FLG_SYN
, // TCP_SYN_SENT
22 TCP_FLG_SYN
| TCP_FLG_ACK
, // TCP_SYN_RCVD
23 TCP_FLG_ACK
, // TCP_ESTABLISHED
24 TCP_FLG_FIN
| TCP_FLG_ACK
, // TCP_FIN_WAIT_1
25 TCP_FLG_ACK
, // TCP_FIN_WAIT_2
26 TCP_FLG_ACK
| TCP_FLG_FIN
, // TCP_CLOSING
27 TCP_FLG_ACK
, // TCP_TIME_WAIT
28 TCP_FLG_ACK
, // TCP_CLOSE_WAIT
29 TCP_FLG_FIN
| TCP_FLG_ACK
// TCP_LAST_ACK
33 Compute the sequence space left in the old receive window.
35 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
37 @return The sequence space left in the old receive window.
49 if (TCP_SEQ_GT (Tcb
->RcvWl2
+ Tcb
->RcvWnd
, Tcb
->RcvNxt
)) {
51 OldWin
= TCP_SUB_SEQ (
52 Tcb
->RcvWl2
+ Tcb
->RcvWnd
,
61 Compute the current receive window.
63 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
65 @return The size of the current receive window, in bytes.
81 OldWin
= TcpRcvWinOld (Tcb
);
83 Win
= SockGetFreeSpace (Sk
, SOCK_RCV_BUF
);
87 Increase
= Win
- OldWin
;
91 // Receiver's SWS: don't advertise a bigger window
92 // unless it can be increased by at least one Mss or
93 // half of the receive buffer.
95 if ((Increase
> Tcb
->SndMss
) || (2 * Increase
>= GET_RCV_BUFFSIZE (Sk
))) {
104 Compute the value to fill in the window size field of the outgoing segment.
106 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
107 @param[in] Syn The flag to indicate whether the outgoing segment
110 @return The value of the local receive window size used to fill the outgoing segment.
122 // RFC requires that initial window not be scaled
126 Wnd
= GET_RCV_BUFFSIZE (Tcb
->Sk
);
129 Wnd
= TcpRcvWinNow (Tcb
);
134 Wnd
= MIN (Wnd
>> Tcb
->RcvWndScale
, 0xffff);
135 return NTOHS ((UINT16
) Wnd
);
139 Get the maximum SndNxt.
141 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
143 @return The sequence number of the maximum SndNxt.
154 if (IsListEmpty (&Tcb
->SndQue
)) {
158 Entry
= Tcb
->SndQue
.BackLink
;
159 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
161 ASSERT (TCP_SEQ_GEQ (TCPSEG_NETBUF (Nbuf
)->End
, Tcb
->SndNxt
));
162 return TCPSEG_NETBUF (Nbuf
)->End
;
166 Compute how much data to send.
168 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
169 @param[in] Force If TRUE, to ignore the sender's SWS avoidance algorithm and send
172 @return The length of the data can be sent. If 0, no data can be sent.
191 // TCP should NOT send data beyond the send window
192 // and congestion window. The right edge of send
193 // window is defined as SND.WL2 + SND.WND. The right
194 // edge of congestion window is defined as SND.UNA +
198 Limit
= Tcb
->SndWl2
+ Tcb
->SndWnd
;
200 if (TCP_SEQ_GT (Limit
, Tcb
->SndUna
+ Tcb
->CWnd
)) {
202 Limit
= Tcb
->SndUna
+ Tcb
->CWnd
;
205 if (TCP_SEQ_GT (Limit
, Tcb
->SndNxt
)) {
206 Win
= TCP_SUB_SEQ (Limit
, Tcb
->SndNxt
);
210 // The data to send contains two parts: the data on the
211 // socket send queue, and the data on the TCB's send
212 // buffer. The later can be non-zero if the peer shrinks
213 // its advertised window.
215 Left
= GET_SND_DATASIZE (Sk
) + TCP_SUB_SEQ (TcpGetMaxSndNxt (Tcb
), Tcb
->SndNxt
);
217 Len
= MIN (Win
, Left
);
219 if (Len
> Tcb
->SndMss
) {
223 if ((Force
!= 0)|| (Len
== 0 && Left
== 0)) {
227 if (Len
== 0 && Left
!= 0) {
228 goto SetPersistTimer
;
232 // Sender's SWS avoidance: Don't send a small segment unless
233 // a)A full-sized segment can be sent,
234 // b)At least one-half of the maximum sized windows that
235 // the other end has ever advertised.
236 // c)It can send everything it has, and either it isn't
237 // expecting an ACK, or the Nagle algorithm is disabled.
239 if ((Len
== Tcb
->SndMss
) || (2 * Len
>= Tcb
->SndWndMax
)) {
245 ((Tcb
->SndNxt
== Tcb
->SndUna
) || TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_NO_NAGLE
))
252 // RFC1122 suggests to set a timer when SWSA forbids TCP
253 // sending more data, and combines it with a probe timer.
256 if (!TCP_TIMER_ON (Tcb
->EnabledTimer
, TCP_TIMER_REXMIT
)) {
260 "TcpDataToSend: enter persistent state for TCB %p\n",
264 if (!Tcb
->ProbeTimerOn
) {
265 TcpSetProbeTimer (Tcb
);
273 Build the TCP header of the TCP segment and transmit the segment by IP.
275 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
276 @param[in] Nbuf Pointer to the buffer containing the segment to be
279 @retval 0 The segment was sent out successfully.
280 @retval -1 An error condition occurred.
295 ASSERT ((Nbuf
!= NULL
) && (Nbuf
->Tcp
== NULL
));
297 if (TcpVerifySegment (Nbuf
) == 0) {
301 DataLen
= Nbuf
->TotalSize
;
303 Seg
= TCPSEG_NETBUF (Nbuf
);
304 Syn
= TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
);
308 Len
= TcpSynBuildOption (Tcb
, Nbuf
);
311 Len
= TcpBuildOption (Tcb
, Nbuf
);
314 ASSERT ((Len
% 4 == 0) && (Len
<= 40));
316 Len
+= sizeof (TCP_HEAD
);
318 Head
= (TCP_HEAD
*) NetbufAllocSpace (
324 ASSERT (Head
!= NULL
);
328 Head
->SrcPort
= Tcb
->LocalEnd
.Port
;
329 Head
->DstPort
= Tcb
->RemoteEnd
.Port
;
330 Head
->Seq
= NTOHL (Seg
->Seq
);
331 Head
->Ack
= NTOHL (Tcb
->RcvNxt
);
332 Head
->HeadLen
= (UINT8
) (Len
>> 2);
334 Head
->Wnd
= TcpComputeWnd (Tcb
, Syn
);
338 // Check whether to set the PSH flag.
340 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_PSH
);
343 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_PSH
) &&
344 TCP_SEQ_BETWEEN (Seg
->Seq
, Tcb
->SndPsh
, Seg
->End
)
347 TCP_SET_FLG (Seg
->Flag
, TCP_FLG_PSH
);
348 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_PSH
);
350 } else if ((Seg
->End
== Tcb
->SndNxt
) && (GET_SND_DATASIZE (Tcb
->Sk
) == 0)) {
352 TCP_SET_FLG (Seg
->Flag
, TCP_FLG_PSH
);
357 // Check whether to set the URG flag and the urgent pointer.
359 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_URG
);
361 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) && TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->SndUp
)) {
363 TCP_SET_FLG (Seg
->Flag
, TCP_FLG_URG
);
365 if (TCP_SEQ_LT (Tcb
->SndUp
, Seg
->End
)) {
367 Seg
->Urg
= (UINT16
) TCP_SUB_SEQ (Tcb
->SndUp
, Seg
->Seq
);
370 Seg
->Urg
= (UINT16
) MIN (
371 TCP_SUB_SEQ (Tcb
->SndUp
,
378 Head
->Flag
= Seg
->Flag
;
379 Head
->Urg
= NTOHS (Seg
->Urg
);
380 Head
->Checksum
= TcpChecksum (Nbuf
, Tcb
->HeadSum
);
383 // Update the TCP session's control information.
385 Tcb
->RcvWl2
= Tcb
->RcvNxt
;
387 Tcb
->RcvWnd
= NTOHS (Head
->Wnd
);
391 // Clear the delayedack flag.
395 return TcpSendIpPacket (Tcb
, Nbuf
, &Tcb
->LocalEnd
.Ip
, &Tcb
->RemoteEnd
.Ip
, Tcb
->Sk
->IpVersion
);
399 Get a segment from the Tcb's SndQue.
401 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
402 @param[in] Seq The sequence number of the segment.
403 @param[in] Len The maximum length of the segment.
405 @return Pointer to the segment. If NULL, some error occurred.
409 TcpGetSegmentSndQue (
426 ASSERT ((Tcb
!= NULL
) && TCP_SEQ_LEQ (Seq
, Tcb
->SndNxt
) && (Len
> 0));
429 // Find the segment that contains the Seq.
436 NET_LIST_FOR_EACH (Cur
, Head
) {
437 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
438 Seg
= TCPSEG_NETBUF (Node
);
440 if (TCP_SEQ_LT (Seq
, Seg
->End
) && TCP_SEQ_LEQ (Seg
->Seq
, Seq
)) {
446 if ((Cur
== Head
) || (Seg
== NULL
) || (Node
== NULL
)) {
451 // Return the buffer if it can be returned without
454 if ((Seg
->Seq
== Seq
) &&
455 TCP_SEQ_LEQ (Seg
->End
, Seg
->Seq
+ Len
) &&
456 !NET_BUF_SHARED (Node
)
464 // Create a new buffer and copy data there.
466 Nbuf
= NetbufAlloc (Len
+ TCP_MAX_HEAD
);
472 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
477 if (TCP_SEQ_LT (Seq
+ Len
, Seg
->End
)) {
481 CopyLen
= TCP_SUB_SEQ (End
, Seq
);
482 Offset
= TCP_SUB_SEQ (Seq
, Seg
->Seq
);
485 // If SYN is set and out of the range, clear the flag.
486 // Becuase the sequence of the first byte is SEG.SEQ+1,
487 // adjust Offset by -1. If SYN is in the range, copy
490 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
492 if (TCP_SEQ_LT (Seg
->Seq
, Seq
)) {
494 TCP_CLEAR_FLG (Flag
, TCP_FLG_SYN
);
503 // If FIN is set and in the range, copy one byte less,
504 // and if it is out of the range, clear the flag.
506 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
508 if (Seg
->End
== End
) {
513 TCP_CLEAR_FLG (Flag
, TCP_FLG_FIN
);
517 ASSERT (CopyLen
>= 0);
520 // Copy data to the segment
523 Data
= NetbufAllocSpace (Nbuf
, CopyLen
, NET_BUF_TAIL
);
524 ASSERT (Data
!= NULL
);
526 if ((INT32
) NetbufCopy (Node
, Offset
, CopyLen
, Data
) != CopyLen
) {
531 CopyMem (TCPSEG_NETBUF (Nbuf
), Seg
, sizeof (TCP_SEG
));
533 TCPSEG_NETBUF (Nbuf
)->Seq
= Seq
;
534 TCPSEG_NETBUF (Nbuf
)->End
= End
;
535 TCPSEG_NETBUF (Nbuf
)->Flag
= Flag
;
545 Get a segment from the Tcb's socket buffer.
547 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
548 @param[in] Seq The sequence number of the segment.
549 @param[in] Len The maximum length of the segment.
551 @return Pointer to the segment. If NULL, some error occurred.
565 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
567 Nbuf
= NetbufAlloc (Len
+ TCP_MAX_HEAD
);
572 "TcpGetSegmentSock: failed to allocate a netbuf for TCB %p\n",
579 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
585 // copy data to the segment.
587 Data
= NetbufAllocSpace (Nbuf
, Len
, NET_BUF_TAIL
);
588 ASSERT (Data
!= NULL
);
590 DataGet
= SockGetDataToSend (Tcb
->Sk
, 0, Len
, Data
);
595 TCPSEG_NETBUF (Nbuf
)->Seq
= Seq
;
596 TCPSEG_NETBUF (Nbuf
)->End
= Seq
+ Len
;
598 InsertTailList (&(Tcb
->SndQue
), &(Nbuf
->List
));
602 SockDataSent (Tcb
->Sk
, DataGet
);
609 Get a segment starting from sequence Seq of a maximum
612 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
613 @param[in] Seq The sequence number of the segment.
614 @param[in] Len The maximum length of the segment.
616 @return Pointer to the segment. If NULL, some error occurred.
628 ASSERT (Tcb
!= NULL
);
631 // Compare the SndNxt with the max sequence number sent.
633 if ((Len
!= 0) && TCP_SEQ_LT (Seq
, TcpGetMaxSndNxt (Tcb
))) {
635 Nbuf
= TcpGetSegmentSndQue (Tcb
, Seq
, Len
);
638 Nbuf
= TcpGetSegmentSock (Tcb
, Seq
, Len
);
641 if (TcpVerifySegment (Nbuf
) == 0) {
650 Retransmit the segment from sequence Seq.
652 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
653 @param[in] Seq The sequence number of the segment to be retransmitted.
655 @retval 0 Retransmission succeeded.
656 @retval -1 Error condition occurred.
669 // Compute the maxium length of retransmission. It is
670 // limited by three factors:
671 // 1. Less than SndMss
672 // 2. Must in the current send window
673 // 3. Will not change the boundaries of queued segments.
677 // Handle the Window Retraction if TCP window scale is enabled according to RFC7323:
678 // On first retransmission, or if the sequence number is out of
679 // window by less than 2^Rcv.Wind.Shift, then do normal
680 // retransmission(s) without regard to the receiver window as long
681 // as the original segment was in window when it was sent.
683 if ((Tcb
->SndWndScale
!= 0) &&
684 (TCP_SEQ_GT (Seq
, Tcb
->RetxmitSeqMax
) || TCP_SEQ_BETWEEN (Tcb
->SndWl2
+ Tcb
->SndWnd
, Seq
, Tcb
->SndWl2
+ Tcb
->SndWnd
+ (1 << Tcb
->SndWndScale
)))) {
685 Len
= TCP_SUB_SEQ (Tcb
->SndNxt
, Seq
);
688 "TcpRetransmit: retransmission without regard to the receiver window for TCB %p\n",
692 } else if (TCP_SEQ_GEQ (Tcb
->SndWl2
+ Tcb
->SndWnd
, Seq
)) {
693 Len
= TCP_SUB_SEQ (Tcb
->SndWl2
+ Tcb
->SndWnd
, Seq
);
698 "TcpRetransmit: retransmission cancelled because send window too small for TCB %p\n",
705 Len
= MIN (Len
, Tcb
->SndMss
);
707 Nbuf
= TcpGetSegmentSndQue (Tcb
, Seq
, Len
);
712 if (TcpVerifySegment (Nbuf
) == 0) {
716 if (TcpTransmitSegment (Tcb
, Nbuf
) != 0) {
720 if (TCP_SEQ_GT (Seq
, Tcb
->RetxmitSeqMax
)) {
721 Tcb
->RetxmitSeqMax
= Seq
;
725 // The retransmitted buffer may be on the SndQue,
726 // trim TCP head because all the buffers on SndQue
729 ASSERT (Nbuf
->Tcp
!= NULL
);
730 NetbufTrim (Nbuf
, (Nbuf
->Tcp
->HeadLen
<< 2), NET_BUF_HEAD
);
745 Verify that all the segments in SndQue are in good shape.
747 @param[in] Head Pointer to the head node of the SndQue.
749 @retval 0 At least one segment is broken.
750 @retval 1 All segments in the specific queue are in good shape.
762 if (IsListEmpty (Head
)) {
766 // Initialize the Seq.
768 Entry
= Head
->ForwardLink
;
769 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
770 Seq
= TCPSEG_NETBUF (Nbuf
)->Seq
;
772 NET_LIST_FOR_EACH (Entry
, Head
) {
773 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
775 if (TcpVerifySegment (Nbuf
) == 0) {
780 // All the node in the SndQue should has:
781 // SEG.SEQ = LAST_SEG.END
783 if (Seq
!= TCPSEG_NETBUF (Nbuf
)->Seq
) {
787 Seq
= TCPSEG_NETBUF (Nbuf
)->End
;
794 Check whether to send data/SYN/FIN and piggyback an ACK.
796 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
797 @param[in] Force If TRUE, ignore the sender's SWS avoidance algorithm
798 and send out data by force.
800 @return The number of bytes sent.
817 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
) && (Tcb
->State
!= TCP_LISTEN
));
821 if ((Tcb
->State
== TCP_CLOSED
) || TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
)) {
828 // Compute how much data can be sent
830 Len
= TcpDataToSend (Tcb
, Force
);
833 ASSERT ((Tcb
->State
) < (ARRAY_SIZE (mTcpOutFlag
)));
834 Flag
= mTcpOutFlag
[Tcb
->State
];
836 if ((Flag
& TCP_FLG_SYN
) != 0) {
843 // Only send a segment without data if SYN or
846 if ((Len
== 0) && ((Flag
& (TCP_FLG_SYN
| TCP_FLG_FIN
)) == 0)) {
850 Nbuf
= TcpGetSegment (Tcb
, Seq
, Len
);
855 "TcpToSendData: failed to get a segment for TCB %p\n",
862 Seg
= TCPSEG_NETBUF (Nbuf
);
865 // Set the TcpSeg in Nbuf.
867 Len
= Nbuf
->TotalSize
;
869 if (TCP_FLG_ON (Flag
, TCP_FLG_SYN
)) {
873 if ((Flag
& TCP_FLG_FIN
) != 0) {
875 // Send FIN if all data is sent, and FIN is
878 if ((TcpGetMaxSndNxt (Tcb
) == Tcb
->SndNxt
) &&
879 (GET_SND_DATASIZE (Tcb
->Sk
) == 0) &&
880 TCP_SEQ_LT (End
+ 1, Tcb
->SndWnd
+ Tcb
->SndWl2
)
884 "TcpToSendData: send FIN to peer for TCB %p in state %s\n",
886 mTcpStateName
[Tcb
->State
])
891 TCP_CLEAR_FLG (Flag
, TCP_FLG_FIN
);
899 if (TcpVerifySegment (Nbuf
) == 0 || TcpCheckSndQue (&Tcb
->SndQue
) == 0) {
902 "TcpToSendData: discard a broken segment for TCB %p\n",
909 // Don't send an empty segment here.
911 if (Seg
->End
== Seg
->Seq
) {
914 "TcpToSendData: created a empty segment for TCB %p, free it now\n",
921 if (TcpTransmitSegment (Tcb
, Nbuf
) != 0) {
922 NetbufTrim (Nbuf
, (Nbuf
->Tcp
->HeadLen
<< 2), NET_BUF_HEAD
);
925 if ((Flag
& TCP_FLG_FIN
) != 0) {
926 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
);
932 Sent
+= TCP_SUB_SEQ (End
, Seq
);
935 // All the buffers in the SndQue are headless.
937 ASSERT (Nbuf
->Tcp
!= NULL
);
939 NetbufTrim (Nbuf
, (Nbuf
->Tcp
->HeadLen
<< 2), NET_BUF_HEAD
);
945 // Update the status in TCB.
949 if ((Flag
& TCP_FLG_FIN
) != 0) {
950 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
);
953 if (TCP_SEQ_GT (End
, Tcb
->SndNxt
)) {
957 if (!TCP_TIMER_ON (Tcb
->EnabledTimer
, TCP_TIMER_REXMIT
)) {
958 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
962 // Enable RTT measurement only if not in retransmit.
963 // Karn's algorithm requires not to update RTT when in loss.
965 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) && !TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
969 "TcpToSendData: set RTT measure sequence %d for TCB %p\n",
974 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
979 } while (Len
== Tcb
->SndMss
);
992 Send an ACK immediately.
994 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
1005 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
1011 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
1013 Seg
= TCPSEG_NETBUF (Nbuf
);
1014 Seg
->Seq
= Tcb
->SndNxt
;
1015 Seg
->End
= Tcb
->SndNxt
;
1016 Seg
->Flag
= TCP_FLG_ACK
;
1018 if (TcpTransmitSegment (Tcb
, Nbuf
) == 0) {
1019 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
1020 Tcb
->DelayedAck
= 0;
1027 Send a zero probe segment. It can be used by keepalive and zero window probe.
1029 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
1031 @retval 0 The zero probe segment was sent out successfully.
1032 @retval other An error condition occurred.
1044 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
1050 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
1053 // SndNxt-1 is out of window. The peer should respond
1056 Seg
= TCPSEG_NETBUF (Nbuf
);
1057 Seg
->Seq
= Tcb
->SndNxt
- 1;
1058 Seg
->End
= Tcb
->SndNxt
- 1;
1059 Seg
->Flag
= TCP_FLG_ACK
;
1061 Result
= TcpTransmitSegment (Tcb
, Nbuf
);
1068 Check whether to send an ACK or delayed ACK.
1070 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
1081 // Generally, TCP should send a delayed ACK unless:
1082 // 1. ACK at least every other FULL sized segment received.
1083 // 2. Packets received out of order.
1084 // 3. Receiving window is open.
1086 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) || (Tcb
->DelayedAck
>= 1)) {
1091 TcpNow
= TcpRcvWinNow (Tcb
);
1093 if (TcpNow
> TcpRcvWinOld (Tcb
)) {
1100 "TcpToSendAck: scheduled a delayed ACK for TCB %p\n",
1105 // Schedule a delayed ACK.
1111 Send a RESET segment in response to the segment received.
1113 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. May be NULL.
1114 @param[in] Head TCP header of the segment that triggers the reset.
1115 @param[in] Len Length of the segment that triggers the reset.
1116 @param[in] Local Local IP address.
1117 @param[in] Remote Remote peer's IP address.
1118 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,
1119 IP_VERSION_6 indicates TCP is running on IP6 stack.
1121 @retval 0 A reset was sent or there is no need to send it.
1122 @retval -1 No reset is sent.
1130 IN EFI_IP_ADDRESS
*Local
,
1131 IN EFI_IP_ADDRESS
*Remote
,
1140 // Don't respond to a Reset with reset.
1142 if ((Head
->Flag
& TCP_FLG_RST
) != 0) {
1146 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
1152 Nhead
= (TCP_HEAD
*) NetbufAllocSpace (
1158 ASSERT (Nhead
!= NULL
);
1161 Nhead
->Flag
= TCP_FLG_RST
;
1164 // Derive Seq/ACK from the segment if no TCB
1165 // is associated with it, otherwise derive from the Tcb.
1169 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_ACK
)) {
1170 Nhead
->Seq
= Head
->Ack
;
1174 TCP_SET_FLG (Nhead
->Flag
, TCP_FLG_ACK
);
1175 Nhead
->Ack
= HTONL (NTOHL (Head
->Seq
) + Len
);
1179 Nhead
->Seq
= HTONL (Tcb
->SndNxt
);
1180 Nhead
->Ack
= HTONL (Tcb
->RcvNxt
);
1181 TCP_SET_FLG (Nhead
->Flag
, TCP_FLG_ACK
);
1184 Nhead
->SrcPort
= Head
->DstPort
;
1185 Nhead
->DstPort
= Head
->SrcPort
;
1186 Nhead
->HeadLen
= (UINT8
) (sizeof (TCP_HEAD
) >> 2);
1188 Nhead
->Wnd
= HTONS (0xFFFF);
1189 Nhead
->Checksum
= 0;
1192 if (Version
== IP_VERSION_4
) {
1193 HeadSum
= NetPseudoHeadChecksum (Local
->Addr
[0], Remote
->Addr
[0], 6, 0);
1195 HeadSum
= NetIp6PseudoHeadChecksum (&Local
->v6
, &Remote
->v6
, 6, 0);
1198 Nhead
->Checksum
= TcpChecksum (Nbuf
, HeadSum
);
1200 TcpSendIpPacket (Tcb
, Nbuf
, Local
, Remote
, Version
);
1208 Verify that the segment is in good shape.
1210 @param[in] Nbuf The buffer that contains the segment to be checked.
1212 @retval 0 The segment is broken.
1213 @retval 1 The segment is in good shape.
1229 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1231 Seg
= TCPSEG_NETBUF (Nbuf
);
1232 Len
= Nbuf
->TotalSize
;
1236 if (Head
->Flag
!= Seg
->Flag
) {
1240 Len
-= (Head
->HeadLen
<< 2);
1243 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1247 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
1251 if (Seg
->Seq
+ Len
!= Seg
->End
) {