]>
git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Output.c
39fbc3b73562c032a075986102dbee4c38fe7b03
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
!= 0)|| (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
) != 0) {
772 // only send a segment without data if SYN or
776 ((Flag
& (TCP_FLG_SYN
| TCP_FLG_FIN
)) == 0)) {
780 Nbuf
= TcpGetSegment (Tcb
, Seq
, Len
);
785 "TcpToSendData: failed to get a segment for TCB %p\n",
792 Seg
= TCPSEG_NETBUF (Nbuf
);
795 // Set the TcpSeg in Nbuf.
797 Len
= Nbuf
->TotalSize
;
799 if (TCP_FLG_ON (Flag
, TCP_FLG_SYN
)) {
803 if ((Flag
& TCP_FLG_FIN
) != 0) {
805 // Send FIN if all data is sent, and FIN is
808 if ((TcpGetMaxSndNxt (Tcb
) == Tcb
->SndNxt
) &&
809 (GET_SND_DATASIZE (Tcb
->Sk
) == 0) &&
810 TCP_SEQ_LT (End
+ 1, Tcb
->SndWnd
+ Tcb
->SndWl2
)
813 DEBUG ((EFI_D_INFO
, "TcpToSendData: send FIN "
814 "to peer for TCB %p in state %d\n", Tcb
, Tcb
->State
));
818 TCP_CLEAR_FLG (Flag
, TCP_FLG_FIN
);
826 ASSERT (TcpVerifySegment (Nbuf
));
827 ASSERT (TcpCheckSndQue (&Tcb
->SndQue
));
830 // don't send an empty segment here.
832 if (Seg
->End
== Seg
->Seq
) {
833 DEBUG ((EFI_D_WARN
, "TcpToSendData: created a empty"
834 " segment for TCB %p, free it now\n", Tcb
));
840 if (TcpTransmitSegment (Tcb
, Nbuf
) != 0) {
842 // TODO: double check this
844 NetbufTrim (Nbuf
, (Nbuf
->Tcp
->HeadLen
<< 2), NET_BUF_HEAD
);
847 if ((Flag
& TCP_FLG_FIN
) != 0) {
848 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
);
854 Sent
+= TCP_SUB_SEQ (End
, Seq
);
857 // All the buffer in the SndQue is headless
861 NetbufTrim (Nbuf
, (Nbuf
->Tcp
->HeadLen
<< 2), NET_BUF_HEAD
);
867 // update status in TCB
871 if ((Flag
& TCP_FLG_FIN
) != 0) {
872 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
);
875 if (TCP_SEQ_GT (End
, Tcb
->SndNxt
)) {
879 if (!TCP_TIMER_ON (Tcb
->EnabledTimer
, TCP_TIMER_REXMIT
)) {
880 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
884 // Enable RTT measurement only if not in retransmit.
885 // Karn's algorithm reqires not to update RTT when in loss.
887 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
888 !TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
890 DEBUG ((EFI_D_INFO
, "TcpToSendData: set RTT measure "
891 "sequence %d for TCB %p\n", Seq
, Tcb
));
893 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
898 if (Len
== Tcb
->SndMss
) {
914 Send an ACK immediately.
916 @param Tcb Pointer to the TCP_CB of this TCP instance.
929 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
935 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
937 Seg
= TCPSEG_NETBUF (Nbuf
);
938 Seg
->Seq
= Tcb
->SndNxt
;
939 Seg
->End
= Tcb
->SndNxt
;
940 Seg
->Flag
= TCP_FLG_ACK
;
942 if (TcpTransmitSegment (Tcb
, Nbuf
) == 0) {
943 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
952 Send a zero probe segment. It can be used by keepalive
953 and zero window probe.
955 @param Tcb Pointer to the TCP_CB of this TCP instance.
957 @retval 0 The zero probe segment was sent out successfully.
958 @retval other Error condition occurred.
970 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
976 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
979 // SndNxt-1 is out of window. The peer should respond
982 Seg
= TCPSEG_NETBUF (Nbuf
);
983 Seg
->Seq
= Tcb
->SndNxt
- 1;
984 Seg
->End
= Tcb
->SndNxt
- 1;
985 Seg
->Flag
= TCP_FLG_ACK
;
987 Result
= TcpTransmitSegment (Tcb
, Nbuf
);
995 Check whether to send an ACK or delayed ACK.
997 @param Tcb Pointer to the TCP_CB of this TCP instance.
1009 TcpNow
= TcpRcvWinNow (Tcb
);
1011 // Generally, TCP should send a delayed ACK unless:
1012 // 1. ACK at least every other FULL sized segment received,
1013 // 2. Packets received out of order
1014 // 3. Receiving window is open
1016 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) ||
1017 (Tcb
->DelayedAck
>= 1) ||
1018 (TcpNow
> TcpRcvWinOld (Tcb
))
1024 DEBUG ((EFI_D_INFO
, "TcpToSendAck: scheduled a delayed"
1025 " ACK for TCB %p\n", Tcb
));
1028 // schedule a delayed ACK
1035 Send a RESET segment in response to the segment received.
1037 @param Tcb Pointer to the TCP_CB of this TCP instance, may be NULL.
1038 @param Head TCP header of the segment that triggers the reset.
1039 @param Len Length of the segment that triggers the reset.
1040 @param Local Local IP address.
1041 @param Remote Remote peer's IP address.
1043 @retval 0 A reset is sent or no need to send it.
1044 @retval -1 No reset is sent.
1061 // Don't respond to a Reset with reset
1063 if (Head
->Flag
& TCP_FLG_RST
) {
1067 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
1073 Nhead
= (TCP_HEAD
*) NetbufAllocSpace (
1079 ASSERT (Nhead
!= NULL
);
1082 Nhead
->Flag
= TCP_FLG_RST
;
1085 // Derive Seq/ACK from the segment if no TCB
1086 // associated with it, otherwise from the Tcb
1090 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_ACK
)) {
1091 Nhead
->Seq
= Head
->Ack
;
1095 TCP_SET_FLG (Nhead
->Flag
, TCP_FLG_ACK
);
1096 Nhead
->Ack
= HTONL (NTOHL (Head
->Seq
) + Len
);
1100 Nhead
->Seq
= HTONL (Tcb
->SndNxt
);
1101 Nhead
->Ack
= HTONL (Tcb
->RcvNxt
);
1102 TCP_SET_FLG (Nhead
->Flag
, TCP_FLG_ACK
);
1105 Nhead
->SrcPort
= Head
->DstPort
;
1106 Nhead
->DstPort
= Head
->SrcPort
;
1107 Nhead
->HeadLen
= (sizeof (TCP_HEAD
) >> 2);
1109 Nhead
->Wnd
= HTONS (0xFFFF);
1110 Nhead
->Checksum
= 0;
1113 HeadSum
= NetPseudoHeadChecksum (Local
, Remote
, 6, 0);
1114 Nhead
->Checksum
= TcpChecksum (Nbuf
, HeadSum
);
1116 TcpSendIpPacket (Tcb
, Nbuf
, Local
, Remote
);
1124 Verify that the segment is in good shape.
1126 @param Nbuf Buffer that contains the segment to be checked.
1128 @retval 0 The segment is broken.
1129 @retval 1 The segment is in good shape.
1145 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1147 Seg
= TCPSEG_NETBUF (Nbuf
);
1148 Len
= Nbuf
->TotalSize
;
1152 if (Head
->Flag
!= Seg
->Flag
) {
1156 Len
-= (Head
->HeadLen
<< 2);
1159 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1163 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
1167 if (Seg
->Seq
+ Len
!= Seg
->End
) {
1176 Verify that all the segments in SndQue are in good shape.
1178 @param Head Pointer to the head node of the SndQue.
1180 @retval 0 At least one segment is broken.
1181 @retval 1 All segments in the specific queue are in good shape.
1193 if (IsListEmpty (Head
)) {
1197 // Initialize the Seq
1199 Entry
= Head
->ForwardLink
;
1200 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1201 Seq
= TCPSEG_NETBUF (Nbuf
)->Seq
;
1203 NET_LIST_FOR_EACH (Entry
, Head
) {
1204 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1206 if (TcpVerifySegment (Nbuf
) == 0) {
1211 // All the node in the SndQue should has:
1212 // SEG.SEQ = LAST_SEG.END
1214 if (Seq
!= TCPSEG_NETBUF (Nbuf
)->Seq
) {
1218 Seq
= TCPSEG_NETBUF (Nbuf
)->End
;