]>
git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Output.c
3 Copyright (c) 2005 - 2006, 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 output process routines.
25 UINT8 mTcpOutFlag
[] = {
28 TCP_FLG_SYN
, // TCP_SYN_SENT
29 TCP_FLG_SYN
| TCP_FLG_ACK
, // TCP_SYN_RCVD
30 TCP_FLG_ACK
, // TCP_ESTABLISHED
31 TCP_FLG_FIN
| TCP_FLG_ACK
, // TCP_FIN_WAIT_1
32 TCP_FLG_ACK
, // TCP_FIN_WAIT_2
33 TCP_FLG_ACK
| TCP_FLG_FIN
, // TCP_CLOSING
34 TCP_FLG_ACK
, // TCP_TIME_WAIT
35 TCP_FLG_ACK
, // TCP_CLOSE_WAIT
36 TCP_FLG_FIN
| TCP_FLG_ACK
// TCP_LAST_ACK
41 Compute the sequence space left in the old receive window.
43 @param Tcb Pointer to the TCP_CB of this TCP instance.
45 @return The sequence space left in the old receive window.
57 if (TCP_SEQ_GT (Tcb
->RcvWl2
+ Tcb
->RcvWnd
, Tcb
->RcvNxt
)) {
59 OldWin
= TCP_SUB_SEQ (
60 Tcb
->RcvWl2
+ Tcb
->RcvWnd
,
70 Compute the current receive window.
72 @param Tcb Pointer to the TCP_CB of this TCP instance.
74 @return The size of the current receive window, in bytes.
90 OldWin
= TcpRcvWinOld (Tcb
);
92 Win
= SockGetFreeSpace (Sk
, SOCK_RCV_BUF
);
96 Increase
= Win
- OldWin
;
100 // Receiver's SWS: don't advertise a bigger window
101 // unless it can be increased by at least one Mss or
102 // half of the receive buffer.
104 if ((Increase
> Tcb
->SndMss
) ||
105 (2 * Increase
>= GET_RCV_BUFFSIZE (Sk
))) {
115 Compute the value to fill in the window size field
116 of the outgoing segment.
118 @param Tcb Pointer to the TCP_CB of this TCP instance.
119 @param Syn The flag to indicate whether the outgoing segment is a SYN
122 @return The value of the local receive window size used to fill the outing segment.
134 // RFC requires that initial window not be scaled
138 Wnd
= GET_RCV_BUFFSIZE (Tcb
->Sk
);
141 Wnd
= TcpRcvWinNow (Tcb
);
146 Wnd
= MIN (Wnd
>> Tcb
->RcvWndScale
, 0xffff);
147 return NTOHS ((UINT16
) Wnd
);
152 Get the maximum SndNxt.
154 @param Tcb Pointer to the TCP_CB of this TCP instance.
156 @return The sequence number of the maximum SndNxt.
167 if (IsListEmpty (&Tcb
->SndQue
)) {
171 Entry
= Tcb
->SndQue
.BackLink
;
172 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
174 ASSERT (TCP_SEQ_GEQ (TCPSEG_NETBUF (Nbuf
)->End
, Tcb
->SndNxt
));
175 return TCPSEG_NETBUF (Nbuf
)->End
;
180 Compute how much data to send.
182 @param Tcb Pointer to the TCP_CB of this TCP instance.
183 @param Force Whether to ignore the sender's SWS avoidance algorithm and send
186 @return The length of the data can be sent, if 0, no data can be sent.
205 // TCP should NOT send data beyond the send window
206 // and congestion window. The right edge of send
207 // window is defined as SND.WL2 + SND.WND. The right
208 // edge of congestion window is defined as SND.UNA +
212 Limit
= Tcb
->SndWl2
+ Tcb
->SndWnd
;
214 if (TCP_SEQ_GT (Limit
, Tcb
->SndUna
+ Tcb
->CWnd
)) {
216 Limit
= Tcb
->SndUna
+ Tcb
->CWnd
;
219 if (TCP_SEQ_GT (Limit
, Tcb
->SndNxt
)) {
220 Win
= TCP_SUB_SEQ (Limit
, Tcb
->SndNxt
);
224 // The data to send contains two parts: the data on the
225 // socket send queue, and the data on the TCB's send
226 // buffer. The later can be non-zero if the peer shrinks
227 // its advertised window.
229 Left
= GET_SND_DATASIZE (Sk
) +
230 TCP_SUB_SEQ (TcpGetMaxSndNxt (Tcb
), Tcb
->SndNxt
);
232 Len
= MIN (Win
, Left
);
234 if (Len
> Tcb
->SndMss
) {
238 if (Force
|| (Len
== 0 && Left
== 0)) {
242 if (Len
== 0 && Left
!= 0) {
243 goto SetPersistTimer
;
247 // Sender's SWS avoidance: Don't send a small segment unless
248 // a)A full-sized segment can be sent,
249 // b)at least one-half of the maximum sized windows that
250 // the other end has ever advertised.
251 // c)It can send everything it has and either it isn't
252 // expecting an ACK or the Nagle algorithm is disabled.
254 if ((Len
== Tcb
->SndMss
) || (2 * Len
>= Tcb
->SndWndMax
)) {
260 ((Tcb
->SndNxt
== Tcb
->SndUna
) ||
261 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_NO_NAGLE
))) {
267 // RFC1122 suggests to set a timer when SWSA forbids TCP
268 // sending more data, and combine it with probe timer.
271 if (!TCP_TIMER_ON (Tcb
->EnabledTimer
, TCP_TIMER_REXMIT
)) {
275 "TcpDataToSend: enter persistent state for TCB %p\n",
279 TcpSetProbeTimer (Tcb
);
287 Build the TCP header of the TCP segment and transmit the
290 @param Tcb Pointer to the TCP_CB of this TCP instance.
291 @param Nbuf Pointer to the buffer containing the segment to be sent out.
293 @retval 0 The segment is sent out successfully.
294 @retval other Error condition occurred.
309 ASSERT (Nbuf
&& (Nbuf
->Tcp
== NULL
) && TcpVerifySegment (Nbuf
));
311 DataLen
= Nbuf
->TotalSize
;
313 Seg
= TCPSEG_NETBUF (Nbuf
);
314 Syn
= TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
);
318 Len
= TcpSynBuildOption (Tcb
, Nbuf
);
321 Len
= TcpBuildOption (Tcb
, Nbuf
);
324 ASSERT ((Len
% 4 == 0) && (Len
<= 40));
326 Len
+= sizeof (TCP_HEAD
);
328 Head
= (TCP_HEAD
*) NetbufAllocSpace (
334 ASSERT (Head
!= NULL
);
338 Head
->SrcPort
= Tcb
->LocalEnd
.Port
;
339 Head
->DstPort
= Tcb
->RemoteEnd
.Port
;
340 Head
->Seq
= NTOHL (Seg
->Seq
);
341 Head
->Ack
= NTOHL (Tcb
->RcvNxt
);
342 Head
->HeadLen
= (UINT8
) (Len
>> 2);
344 Head
->Wnd
= TcpComputeWnd (Tcb
, Syn
);
348 // Check whether to set the PSH flag.
350 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_PSH
);
353 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_PSH
) &&
354 TCP_SEQ_BETWEEN (Seg
->Seq
, Tcb
->SndPsh
, Seg
->End
)) {
356 TCP_SET_FLG (Seg
->Flag
, TCP_FLG_PSH
);
357 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_PSH
);
359 } else if ((Seg
->End
== Tcb
->SndNxt
) &&
360 (GET_SND_DATASIZE (Tcb
->Sk
) == 0)) {
362 TCP_SET_FLG (Seg
->Flag
, TCP_FLG_PSH
);
367 // Check whether to set the URG flag and the urgent pointer.
369 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_URG
);
371 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
372 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->SndUp
)) {
374 TCP_SET_FLG (Seg
->Flag
, TCP_FLG_URG
);
376 if (TCP_SEQ_LT (Tcb
->SndUp
, Seg
->End
)) {
378 Seg
->Urg
= (UINT16
) TCP_SUB_SEQ (Tcb
->SndUp
, Seg
->Seq
);
381 Seg
->Urg
= (UINT16
) MIN (
382 TCP_SUB_SEQ (Tcb
->SndUp
,
389 Head
->Flag
= Seg
->Flag
;
390 Head
->Urg
= NTOHS (Seg
->Urg
);
391 Head
->Checksum
= TcpChecksum (Nbuf
, Tcb
->HeadSum
);
394 // update the TCP session's control information
396 Tcb
->RcvWl2
= Tcb
->RcvNxt
;
398 Tcb
->RcvWnd
= NTOHS (Head
->Wnd
);
402 // clear delayedack flag
406 return TcpSendIpPacket (Tcb
, Nbuf
, Tcb
->LocalEnd
.Ip
, Tcb
->RemoteEnd
.Ip
);
411 Get a segment from the Tcb's SndQue.
413 @param Tcb Pointer to the TCP_CB of this TCP instance.
414 @param Seq The sequence number of the segment.
415 @param Len The maximum length of the segment.
417 @return Pointer to the segment, if NULL some error occurred.
421 TcpGetSegmentSndQue (
438 ASSERT (Tcb
&& TCP_SEQ_LEQ (Seq
, Tcb
->SndNxt
) && (Len
> 0));
441 // Find the segment that contains the Seq.
448 NET_LIST_FOR_EACH (Cur
, Head
) {
449 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
450 Seg
= TCPSEG_NETBUF (Node
);
452 if (TCP_SEQ_LT (Seq
, Seg
->End
) && TCP_SEQ_LEQ (Seg
->Seq
, Seq
)) {
458 ASSERT (Cur
!= Head
);
461 // Return the buffer if it can be returned without
464 if ((Seg
->Seq
== Seq
) &&
465 TCP_SEQ_LEQ (Seg
->End
, Seg
->Seq
+ Len
) &&
466 !NET_BUF_SHARED (Node
)) {
473 // Create a new buffer and copy data there.
475 Nbuf
= NetbufAlloc (Len
+ TCP_MAX_HEAD
);
481 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
486 if (TCP_SEQ_LT (Seq
+ Len
, Seg
->End
)) {
490 CopyLen
= TCP_SUB_SEQ (End
, Seq
);
491 Offset
= TCP_SUB_SEQ (Seq
, Seg
->Seq
);
494 // If SYN is set and out of the range, clear the flag.
495 // Becuase the sequence of the first byte is SEG.SEQ+1,
496 // adjust Offset by -1. If SYN is in the range, copy
499 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
501 if (TCP_SEQ_LT (Seg
->Seq
, Seq
)) {
503 TCP_CLEAR_FLG (Flag
, TCP_FLG_SYN
);
512 // If FIN is set and in the range, copy one byte less,
513 // and if it is out of the range, clear the flag.
515 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
517 if (Seg
->End
== End
) {
522 TCP_CLEAR_FLG (Flag
, TCP_FLG_FIN
);
526 ASSERT (CopyLen
>= 0);
529 // copy data to the segment
532 Data
= NetbufAllocSpace (Nbuf
, CopyLen
, NET_BUF_TAIL
);
535 if ((INT32
) NetbufCopy (Node
, Offset
, CopyLen
, Data
) != CopyLen
) {
540 CopyMem (TCPSEG_NETBUF (Nbuf
), Seg
, sizeof (TCP_SEG
));
542 TCPSEG_NETBUF (Nbuf
)->Seq
= Seq
;
543 TCPSEG_NETBUF (Nbuf
)->End
= End
;
544 TCPSEG_NETBUF (Nbuf
)->Flag
= Flag
;
555 Get a segment from the Tcb's socket buffer.
557 @param Tcb Pointer to the TCP_CB of this TCP instance.
558 @param Seq The sequence number of the segment.
559 @param Len The maximum length of the segment.
561 @return Pointer to the segment, if NULL some error occurred.
575 ASSERT (Tcb
&& Tcb
->Sk
);
577 Nbuf
= NetbufAlloc (Len
+ TCP_MAX_HEAD
);
580 DEBUG ((EFI_D_ERROR
, "TcpGetSegmentSock: failed to allocate "
581 "a netbuf for TCB %p\n",Tcb
));
586 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
592 // copy data to the segment.
594 Data
= NetbufAllocSpace (Nbuf
, Len
, NET_BUF_TAIL
);
597 DataGet
= SockGetDataToSend (Tcb
->Sk
, 0, Len
, Data
);
602 TCPSEG_NETBUF (Nbuf
)->Seq
= Seq
;
603 TCPSEG_NETBUF (Nbuf
)->End
= Seq
+ Len
;
605 InsertTailList (&(Tcb
->SndQue
), &(Nbuf
->List
));
609 SockDataSent (Tcb
->Sk
, DataGet
);
617 Get a segment starting from sequence Seq of a maximum
620 @param Tcb Pointer to the TCP_CB of this TCP instance.
621 @param Seq The sequence number of the segment.
622 @param Len The maximum length of the segment.
624 @return Pointer to the segment, if NULL some error occurred.
639 // Compare the SndNxt with the max sequence number sent.
641 if ((Len
!= 0) && TCP_SEQ_LT (Seq
, TcpGetMaxSndNxt (Tcb
))) {
643 Nbuf
= TcpGetSegmentSndQue (Tcb
, Seq
, Len
);
646 Nbuf
= TcpGetSegmentSock (Tcb
, Seq
, Len
);
649 ASSERT (TcpVerifySegment (Nbuf
));
655 Retransmit the segment from sequence Seq.
657 @param Tcb Pointer to the TCP_CB of this TCP instance.
658 @param Seq The sequence number of the segment to be retransmitted.
660 @retval 0 Retransmission succeeded.
661 @retval -1 Error condition occurred.
674 // Compute the maxium length of retransmission. It is
675 // limited by three factors:
676 // 1. Less than SndMss
677 // 2. must in the current send window
678 // 3. will not change the boundaries of queued segments.
680 if (TCP_SEQ_LT (Tcb
->SndWl2
+ Tcb
->SndWnd
, Seq
)) {
681 DEBUG ((EFI_D_WARN
, "TcpRetransmit: retransmission cancelled "
682 "because send window too small for TCB %p\n", Tcb
));
687 Len
= TCP_SUB_SEQ (Tcb
->SndWl2
+ Tcb
->SndWnd
, Seq
);
688 Len
= MIN (Len
, Tcb
->SndMss
);
690 Nbuf
= TcpGetSegmentSndQue (Tcb
, Seq
, Len
);
695 ASSERT (TcpVerifySegment (Nbuf
));
697 if (TcpTransmitSegment (Tcb
, Nbuf
) != 0) {
702 // The retransmitted buffer may be on the SndQue,
703 // trim TCP head because all the buffer on SndQue
707 NetbufTrim (Nbuf
, (Nbuf
->Tcp
->HeadLen
<< 2), NET_BUF_HEAD
);
723 Check whether to send data/SYN/FIN and piggy back an ACK.
725 @param Tcb Pointer to the TCP_CB of this TCP instance.
726 @param Force Whether to ignore the sender's SWS avoidance algorithm and send
729 @return The number of bytes sent.
746 ASSERT (Tcb
&& Tcb
->Sk
&& (Tcb
->State
!= TCP_LISTEN
));
750 if ((Tcb
->State
== TCP_CLOSED
) ||
751 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
)) {
758 // compute how much data can be sent
760 Len
= TcpDataToSend (Tcb
, Force
);
763 Flag
= mTcpOutFlag
[Tcb
->State
];
765 if (Flag
& TCP_FLG_SYN
) {
772 // only send a segment without data if SYN or
775 if ((Len
== 0) && !(Flag
& (TCP_FLG_SYN
| TCP_FLG_FIN
))) {
779 Nbuf
= TcpGetSegment (Tcb
, Seq
, Len
);
784 "TcpToSendData: failed to get a segment for TCB %p\n",
791 Seg
= TCPSEG_NETBUF (Nbuf
);
794 // Set the TcpSeg in Nbuf.
796 Len
= Nbuf
->TotalSize
;
798 if (TCP_FLG_ON (Flag
, TCP_FLG_SYN
)) {
802 if (Flag
& TCP_FLG_FIN
) {
804 // Send FIN if all data is sent, and FIN is
807 if ((TcpGetMaxSndNxt (Tcb
) == Tcb
->SndNxt
) &&
808 (GET_SND_DATASIZE (Tcb
->Sk
) == 0) &&
809 TCP_SEQ_LT (End
+ 1, Tcb
->SndWnd
+ Tcb
->SndWl2
)
812 DEBUG ((EFI_D_INFO
, "TcpToSendData: send FIN "
813 "to peer for TCB %p in state %d\n", Tcb
, Tcb
->State
));
817 TCP_CLEAR_FLG (Flag
, TCP_FLG_FIN
);
825 ASSERT (TcpVerifySegment (Nbuf
));
826 ASSERT (TcpCheckSndQue (&Tcb
->SndQue
));
829 // don't send an empty segment here.
831 if (Seg
->End
== Seg
->Seq
) {
832 DEBUG ((EFI_D_WARN
, "TcpToSendData: created a empty"
833 " segment for TCB %p, free it now\n", Tcb
));
839 if (TcpTransmitSegment (Tcb
, Nbuf
) != 0) {
841 // TODO: double check this
843 NetbufTrim (Nbuf
, (Nbuf
->Tcp
->HeadLen
<< 2), NET_BUF_HEAD
);
846 if (Flag
& TCP_FLG_FIN
) {
847 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
);
853 Sent
+= TCP_SUB_SEQ (End
, Seq
);
856 // All the buffer in the SndQue is headless
860 NetbufTrim (Nbuf
, (Nbuf
->Tcp
->HeadLen
<< 2), NET_BUF_HEAD
);
866 // update status in TCB
870 if (Flag
& TCP_FLG_FIN
) {
871 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
);
874 if (TCP_SEQ_GT (End
, Tcb
->SndNxt
)) {
878 if (!TCP_TIMER_ON (Tcb
->EnabledTimer
, TCP_TIMER_REXMIT
)) {
879 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
883 // Enable RTT measurement only if not in retransmit.
884 // Karn's algorithm reqires not to update RTT when in loss.
886 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
887 !TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
889 DEBUG ((EFI_D_INFO
, "TcpToSendData: set RTT measure "
890 "sequence %d for TCB %p\n", Seq
, Tcb
));
892 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
897 if (Len
== Tcb
->SndMss
) {
913 Send an ACK immediately.
915 @param Tcb Pointer to the TCP_CB of this TCP instance.
928 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
934 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
936 Seg
= TCPSEG_NETBUF (Nbuf
);
937 Seg
->Seq
= Tcb
->SndNxt
;
938 Seg
->End
= Tcb
->SndNxt
;
939 Seg
->Flag
= TCP_FLG_ACK
;
941 if (TcpTransmitSegment (Tcb
, Nbuf
) == 0) {
942 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
951 Send a zero probe segment. It can be used by keepalive
952 and zero window probe.
954 @param Tcb Pointer to the TCP_CB of this TCP instance.
956 @retval 0 The zero probe segment was sent out successfully.
957 @retval other Error condition occurred.
969 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
975 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
978 // SndNxt-1 is out of window. The peer should respond
981 Seg
= TCPSEG_NETBUF (Nbuf
);
982 Seg
->Seq
= Tcb
->SndNxt
- 1;
983 Seg
->End
= Tcb
->SndNxt
- 1;
984 Seg
->Flag
= TCP_FLG_ACK
;
986 Result
= TcpTransmitSegment (Tcb
, Nbuf
);
994 Check whether to send an ACK or delayed ACK.
996 @param Tcb Pointer to the TCP_CB of this TCP instance.
1008 TcpNow
= TcpRcvWinNow (Tcb
);
1010 // Generally, TCP should send a delayed ACK unless:
1011 // 1. ACK at least every other FULL sized segment received,
1012 // 2. Packets received out of order
1013 // 3. Receiving window is open
1015 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) ||
1016 (Tcb
->DelayedAck
>= 1) ||
1017 (TcpNow
> TcpRcvWinOld (Tcb
))
1023 DEBUG ((EFI_D_INFO
, "TcpToSendAck: scheduled a delayed"
1024 " ACK for TCB %p\n", Tcb
));
1027 // schedule a delayed ACK
1034 Send a RESET segment in response to the segment received.
1036 @param Tcb Pointer to the TCP_CB of this TCP instance, may be NULL.
1037 @param Head TCP header of the segment that triggers the reset.
1038 @param Len Length of the segment that triggers the reset.
1039 @param Local Local IP address.
1040 @param Remote Remote peer's IP address.
1042 @retval 0 A reset is sent or no need to send it.
1043 @retval -1 No reset is sent.
1060 // Don't respond to a Reset with reset
1062 if (Head
->Flag
& TCP_FLG_RST
) {
1066 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
1072 Nhead
= (TCP_HEAD
*) NetbufAllocSpace (
1078 ASSERT (Nhead
!= NULL
);
1081 Nhead
->Flag
= TCP_FLG_RST
;
1084 // Derive Seq/ACK from the segment if no TCB
1085 // associated with it, otherwise from the Tcb
1089 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_ACK
)) {
1090 Nhead
->Seq
= Head
->Ack
;
1094 TCP_SET_FLG (Nhead
->Flag
, TCP_FLG_ACK
);
1095 Nhead
->Ack
= HTONL (NTOHL (Head
->Seq
) + Len
);
1099 Nhead
->Seq
= HTONL (Tcb
->SndNxt
);
1100 Nhead
->Ack
= HTONL (Tcb
->RcvNxt
);
1101 TCP_SET_FLG (Nhead
->Flag
, TCP_FLG_ACK
);
1104 Nhead
->SrcPort
= Head
->DstPort
;
1105 Nhead
->DstPort
= Head
->SrcPort
;
1106 Nhead
->HeadLen
= (sizeof (TCP_HEAD
) >> 2);
1108 Nhead
->Wnd
= HTONS (0xFFFF);
1109 Nhead
->Checksum
= 0;
1112 HeadSum
= NetPseudoHeadChecksum (Local
, Remote
, 6, 0);
1113 Nhead
->Checksum
= TcpChecksum (Nbuf
, HeadSum
);
1115 TcpSendIpPacket (Tcb
, Nbuf
, Local
, Remote
);
1123 Verify that the segment is in good shape.
1125 @param Nbuf Buffer that contains the segment to be checked.
1127 @retval 0 The segment is broken.
1128 @retval 1 The segment is in good shape.
1144 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1146 Seg
= TCPSEG_NETBUF (Nbuf
);
1147 Len
= Nbuf
->TotalSize
;
1151 if (Head
->Flag
!= Seg
->Flag
) {
1155 Len
-= (Head
->HeadLen
<< 2);
1158 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1162 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
1166 if (Seg
->Seq
+ Len
!= Seg
->End
) {
1175 Verify that all the segments in SndQue are in good shape.
1177 @param Head Pointer to the head node of the SndQue.
1179 @retval 0 At least one segment is broken.
1180 @retval 1 All segments in the specific queue are in good shape.
1192 if (IsListEmpty (Head
)) {
1196 // Initialize the Seq
1198 Entry
= Head
->ForwardLink
;
1199 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1200 Seq
= TCPSEG_NETBUF (Nbuf
)->Seq
;
1202 NET_LIST_FOR_EACH (Entry
, Head
) {
1203 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1205 if (TcpVerifySegment (Nbuf
) == 0) {
1210 // All the node in the SndQue should has:
1211 // SEG.SEQ = LAST_SEG.END
1213 if (Seq
!= TCPSEG_NETBUF (Nbuf
)->Seq
) {
1217 Seq
= TCPSEG_NETBUF (Nbuf
)->End
;