]>
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
!= 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 segment by IP.
289 @param Tcb Pointer to the TCP_CB of this TCP instance.
290 @param Nbuf Pointer to the buffer containing the segment to be sent out.
292 @retval 0 The segment is sent out successfully.
293 @retval other Error condition occurred.
308 ASSERT ((Nbuf
!= NULL
) && (Nbuf
->Tcp
== NULL
) && (TcpVerifySegment (Nbuf
) != 0));
310 DataLen
= Nbuf
->TotalSize
;
312 Seg
= TCPSEG_NETBUF (Nbuf
);
313 Syn
= TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
);
317 Len
= TcpSynBuildOption (Tcb
, Nbuf
);
320 Len
= TcpBuildOption (Tcb
, Nbuf
);
323 ASSERT ((Len
% 4 == 0) && (Len
<= 40));
325 Len
+= sizeof (TCP_HEAD
);
327 Head
= (TCP_HEAD
*) NetbufAllocSpace (
333 ASSERT (Head
!= NULL
);
337 Head
->SrcPort
= Tcb
->LocalEnd
.Port
;
338 Head
->DstPort
= Tcb
->RemoteEnd
.Port
;
339 Head
->Seq
= NTOHL (Seg
->Seq
);
340 Head
->Ack
= NTOHL (Tcb
->RcvNxt
);
341 Head
->HeadLen
= (UINT8
) (Len
>> 2);
343 Head
->Wnd
= TcpComputeWnd (Tcb
, Syn
);
347 // Check whether to set the PSH flag.
349 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_PSH
);
352 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_PSH
) &&
353 TCP_SEQ_BETWEEN (Seg
->Seq
, Tcb
->SndPsh
, Seg
->End
)) {
355 TCP_SET_FLG (Seg
->Flag
, TCP_FLG_PSH
);
356 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_PSH
);
358 } else if ((Seg
->End
== Tcb
->SndNxt
) &&
359 (GET_SND_DATASIZE (Tcb
->Sk
) == 0)) {
361 TCP_SET_FLG (Seg
->Flag
, TCP_FLG_PSH
);
366 // Check whether to set the URG flag and the urgent pointer.
368 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_URG
);
370 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
371 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->SndUp
)) {
373 TCP_SET_FLG (Seg
->Flag
, TCP_FLG_URG
);
375 if (TCP_SEQ_LT (Tcb
->SndUp
, Seg
->End
)) {
377 Seg
->Urg
= (UINT16
) TCP_SUB_SEQ (Tcb
->SndUp
, Seg
->Seq
);
380 Seg
->Urg
= (UINT16
) MIN (
381 TCP_SUB_SEQ (Tcb
->SndUp
,
388 Head
->Flag
= Seg
->Flag
;
389 Head
->Urg
= NTOHS (Seg
->Urg
);
390 Head
->Checksum
= TcpChecksum (Nbuf
, Tcb
->HeadSum
);
393 // update the TCP session's control information
395 Tcb
->RcvWl2
= Tcb
->RcvNxt
;
397 Tcb
->RcvWnd
= NTOHS (Head
->Wnd
);
401 // clear delayedack flag
405 return TcpSendIpPacket (Tcb
, Nbuf
, Tcb
->LocalEnd
.Ip
, Tcb
->RemoteEnd
.Ip
);
410 Get a segment from the Tcb's SndQue.
412 @param Tcb Pointer to the TCP_CB of this TCP instance.
413 @param Seq The sequence number of the segment.
414 @param Len The maximum length of the segment.
416 @return Pointer to the segment, if NULL some error occurred.
420 TcpGetSegmentSndQue (
437 ASSERT ((Tcb
!= NULL
) && TCP_SEQ_LEQ (Seq
, Tcb
->SndNxt
) && (Len
> 0));
440 // Find the segment that contains the Seq.
447 NET_LIST_FOR_EACH (Cur
, Head
) {
448 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
449 Seg
= TCPSEG_NETBUF (Node
);
451 if (TCP_SEQ_LT (Seq
, Seg
->End
) && TCP_SEQ_LEQ (Seg
->Seq
, Seq
)) {
457 ASSERT (Cur
!= Head
);
460 // Return the buffer if it can be returned without
463 if ((Seg
->Seq
== Seq
) &&
464 TCP_SEQ_LEQ (Seg
->End
, Seg
->Seq
+ Len
) &&
465 !NET_BUF_SHARED (Node
)) {
472 // Create a new buffer and copy data there.
474 Nbuf
= NetbufAlloc (Len
+ TCP_MAX_HEAD
);
480 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
485 if (TCP_SEQ_LT (Seq
+ Len
, Seg
->End
)) {
489 CopyLen
= TCP_SUB_SEQ (End
, Seq
);
490 Offset
= TCP_SUB_SEQ (Seq
, Seg
->Seq
);
493 // If SYN is set and out of the range, clear the flag.
494 // Becuase the sequence of the first byte is SEG.SEQ+1,
495 // adjust Offset by -1. If SYN is in the range, copy
498 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
500 if (TCP_SEQ_LT (Seg
->Seq
, Seq
)) {
502 TCP_CLEAR_FLG (Flag
, TCP_FLG_SYN
);
511 // If FIN is set and in the range, copy one byte less,
512 // and if it is out of the range, clear the flag.
514 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
516 if (Seg
->End
== End
) {
521 TCP_CLEAR_FLG (Flag
, TCP_FLG_FIN
);
525 ASSERT (CopyLen
>= 0);
528 // copy data to the segment
531 Data
= NetbufAllocSpace (Nbuf
, CopyLen
, NET_BUF_TAIL
);
532 ASSERT (Data
!= NULL
);
534 if ((INT32
) NetbufCopy (Node
, Offset
, CopyLen
, Data
) != CopyLen
) {
539 CopyMem (TCPSEG_NETBUF (Nbuf
), Seg
, sizeof (TCP_SEG
));
541 TCPSEG_NETBUF (Nbuf
)->Seq
= Seq
;
542 TCPSEG_NETBUF (Nbuf
)->End
= End
;
543 TCPSEG_NETBUF (Nbuf
)->Flag
= Flag
;
554 Get a segment from the Tcb's socket buffer.
556 @param Tcb Pointer to the TCP_CB of this TCP instance.
557 @param Seq The sequence number of the segment.
558 @param Len The maximum length of the segment.
560 @return Pointer to the segment, if NULL some error occurred.
574 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
));
576 Nbuf
= NetbufAlloc (Len
+ TCP_MAX_HEAD
);
579 DEBUG ((EFI_D_ERROR
, "TcpGetSegmentSock: failed to allocate "
580 "a netbuf for TCB %p\n",Tcb
));
585 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
591 // copy data to the segment.
593 Data
= NetbufAllocSpace (Nbuf
, Len
, NET_BUF_TAIL
);
594 ASSERT (Data
!= NULL
);
596 DataGet
= SockGetDataToSend (Tcb
->Sk
, 0, Len
, Data
);
601 TCPSEG_NETBUF (Nbuf
)->Seq
= Seq
;
602 TCPSEG_NETBUF (Nbuf
)->End
= Seq
+ Len
;
604 InsertTailList (&(Tcb
->SndQue
), &(Nbuf
->List
));
608 SockDataSent (Tcb
->Sk
, DataGet
);
616 Get a segment starting from sequence Seq of a maximum
619 @param Tcb Pointer to the TCP_CB of this TCP instance.
620 @param Seq The sequence number of the segment.
621 @param Len The maximum length of the segment.
623 @return Pointer to the segment, if NULL some error occurred.
635 ASSERT (Tcb
!= NULL
);
638 // Compare the SndNxt with the max sequence number sent.
640 if ((Len
!= 0) && TCP_SEQ_LT (Seq
, TcpGetMaxSndNxt (Tcb
))) {
642 Nbuf
= TcpGetSegmentSndQue (Tcb
, Seq
, Len
);
645 Nbuf
= TcpGetSegmentSock (Tcb
, Seq
, Len
);
648 ASSERT (TcpVerifySegment (Nbuf
) != 0);
654 Retransmit the segment from sequence Seq.
656 @param Tcb Pointer to the TCP_CB of this TCP instance.
657 @param Seq The sequence number of the segment to be retransmitted.
659 @retval 0 Retransmission succeeded.
660 @retval -1 Error condition occurred.
673 // Compute the maxium length of retransmission. It is
674 // limited by three factors:
675 // 1. Less than SndMss
676 // 2. must in the current send window
677 // 3. will not change the boundaries of queued segments.
679 if (TCP_SEQ_LT (Tcb
->SndWl2
+ Tcb
->SndWnd
, Seq
)) {
680 DEBUG ((EFI_D_WARN
, "TcpRetransmit: retransmission cancelled "
681 "because send window too small for TCB %p\n", Tcb
));
686 Len
= TCP_SUB_SEQ (Tcb
->SndWl2
+ Tcb
->SndWnd
, Seq
);
687 Len
= MIN (Len
, Tcb
->SndMss
);
689 Nbuf
= TcpGetSegmentSndQue (Tcb
, Seq
, Len
);
694 ASSERT (TcpVerifySegment (Nbuf
) != 0);
696 if (TcpTransmitSegment (Tcb
, Nbuf
) != 0) {
701 // The retransmitted buffer may be on the SndQue,
702 // trim TCP head because all the buffer on SndQue
705 ASSERT (Nbuf
->Tcp
!= NULL
);
706 NetbufTrim (Nbuf
, (Nbuf
->Tcp
->HeadLen
<< 2), NET_BUF_HEAD
);
722 Check whether to send data/SYN/FIN and piggy back an ACK.
724 @param Tcb Pointer to the TCP_CB of this TCP instance.
725 @param Force Whether to ignore the sender's SWS avoidance algorithm and send
728 @return The number of bytes sent.
745 ASSERT ((Tcb
!= NULL
) && (Tcb
->Sk
!= NULL
) && (Tcb
->State
!= TCP_LISTEN
));
749 if ((Tcb
->State
== TCP_CLOSED
) ||
750 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
)) {
757 // compute how much data can be sent
759 Len
= TcpDataToSend (Tcb
, Force
);
762 Flag
= mTcpOutFlag
[Tcb
->State
];
764 if ((Flag
& TCP_FLG_SYN
) != 0) {
771 // only send a segment without data if SYN or
775 ((Flag
& (TCP_FLG_SYN
| TCP_FLG_FIN
)) == 0)) {
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
) != 0) {
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
)) {
811 DEBUG ((EFI_D_INFO
, "TcpToSendData: send FIN "
812 "to peer for TCB %p in state %d\n", Tcb
, Tcb
->State
));
816 TCP_CLEAR_FLG (Flag
, TCP_FLG_FIN
);
824 ASSERT (TcpVerifySegment (Nbuf
) != 0);
825 ASSERT (TcpCheckSndQue (&Tcb
->SndQue
) != 0);
828 // don't send an empty segment here.
830 if (Seg
->End
== Seg
->Seq
) {
831 DEBUG ((EFI_D_WARN
, "TcpToSendData: created a empty"
832 " segment for TCB %p, free it now\n", Tcb
));
838 if (TcpTransmitSegment (Tcb
, Nbuf
) != 0) {
840 // TODO: double check this
842 NetbufTrim (Nbuf
, (Nbuf
->Tcp
->HeadLen
<< 2), NET_BUF_HEAD
);
845 if ((Flag
& TCP_FLG_FIN
) != 0) {
846 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
);
852 Sent
+= TCP_SUB_SEQ (End
, Seq
);
855 // All the buffer in the SndQue is headless
857 ASSERT (Nbuf
->Tcp
!= NULL
);
859 NetbufTrim (Nbuf
, (Nbuf
->Tcp
->HeadLen
<< 2), NET_BUF_HEAD
);
865 // update status in TCB
869 if ((Flag
& TCP_FLG_FIN
) != 0) {
870 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
);
873 if (TCP_SEQ_GT (End
, Tcb
->SndNxt
)) {
877 if (!TCP_TIMER_ON (Tcb
->EnabledTimer
, TCP_TIMER_REXMIT
)) {
878 TcpSetTimer (Tcb
, TCP_TIMER_REXMIT
, Tcb
->Rto
);
882 // Enable RTT measurement only if not in retransmit.
883 // Karn's algorithm reqires not to update RTT when in loss.
885 if ((Tcb
->CongestState
== TCP_CONGEST_OPEN
) &&
886 !TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
)) {
888 DEBUG ((EFI_D_INFO
, "TcpToSendData: set RTT measure "
889 "sequence %d for TCB %p\n", Seq
, Tcb
));
891 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RTT_ON
);
896 if (Len
== Tcb
->SndMss
) {
912 Send an ACK immediately.
914 @param Tcb Pointer to the TCP_CB of this TCP instance.
925 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
931 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
933 Seg
= TCPSEG_NETBUF (Nbuf
);
934 Seg
->Seq
= Tcb
->SndNxt
;
935 Seg
->End
= Tcb
->SndNxt
;
936 Seg
->Flag
= TCP_FLG_ACK
;
938 if (TcpTransmitSegment (Tcb
, Nbuf
) == 0) {
939 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
);
948 Send a zero probe segment. It can be used by keepalive and zero window probe.
950 @param Tcb Pointer to the TCP_CB of this TCP instance.
952 @retval 0 The zero probe segment was sent out successfully.
953 @retval other Error condition occurred.
965 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
971 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
974 // SndNxt-1 is out of window. The peer should respond
977 Seg
= TCPSEG_NETBUF (Nbuf
);
978 Seg
->Seq
= Tcb
->SndNxt
- 1;
979 Seg
->End
= Tcb
->SndNxt
- 1;
980 Seg
->Flag
= TCP_FLG_ACK
;
982 Result
= TcpTransmitSegment (Tcb
, Nbuf
);
990 Check whether to send an ACK or delayed ACK.
992 @param Tcb Pointer to the TCP_CB of this TCP instance.
1002 TcpNow
= TcpRcvWinNow (Tcb
);
1004 // Generally, TCP should send a delayed ACK unless:
1005 // 1. ACK at least every other FULL sized segment received,
1006 // 2. Packets received out of order
1007 // 3. Receiving window is open
1009 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_ACK_NOW
) ||
1010 (Tcb
->DelayedAck
>= 1) ||
1011 (TcpNow
> TcpRcvWinOld (Tcb
))) {
1016 DEBUG ((EFI_D_INFO
, "TcpToSendAck: scheduled a delayed"
1017 " ACK for TCB %p\n", Tcb
));
1020 // schedule a delayed ACK
1027 Send a RESET segment in response to the segment received.
1029 @param Tcb Pointer to the TCP_CB of this TCP instance, may be NULL.
1030 @param Head TCP header of the segment that triggers the reset.
1031 @param Len Length of the segment that triggers the reset.
1032 @param Local Local IP address.
1033 @param Remote Remote peer's IP address.
1035 @retval 0 A reset is sent or no need to send it.
1036 @retval -1 No reset is sent.
1053 // Don't respond to a Reset with reset
1055 if ((Head
->Flag
& TCP_FLG_RST
) != 0) {
1059 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
1065 Nhead
= (TCP_HEAD
*) NetbufAllocSpace (
1071 ASSERT (Nhead
!= NULL
);
1074 Nhead
->Flag
= TCP_FLG_RST
;
1077 // Derive Seq/ACK from the segment if no TCB
1078 // associated with it, otherwise from the Tcb
1082 if (TCP_FLG_ON (Head
->Flag
, TCP_FLG_ACK
)) {
1083 Nhead
->Seq
= Head
->Ack
;
1087 TCP_SET_FLG (Nhead
->Flag
, TCP_FLG_ACK
);
1088 Nhead
->Ack
= HTONL (NTOHL (Head
->Seq
) + Len
);
1092 Nhead
->Seq
= HTONL (Tcb
->SndNxt
);
1093 Nhead
->Ack
= HTONL (Tcb
->RcvNxt
);
1094 TCP_SET_FLG (Nhead
->Flag
, TCP_FLG_ACK
);
1097 Nhead
->SrcPort
= Head
->DstPort
;
1098 Nhead
->DstPort
= Head
->SrcPort
;
1099 Nhead
->HeadLen
= (sizeof (TCP_HEAD
) >> 2);
1101 Nhead
->Wnd
= HTONS (0xFFFF);
1102 Nhead
->Checksum
= 0;
1105 HeadSum
= NetPseudoHeadChecksum (Local
, Remote
, 6, 0);
1106 Nhead
->Checksum
= TcpChecksum (Nbuf
, HeadSum
);
1108 TcpSendIpPacket (Tcb
, Nbuf
, Local
, Remote
);
1116 Verify that the segment is in good shape.
1118 @param Nbuf Buffer that contains the segment to be checked.
1120 @retval 0 The segment is broken.
1121 @retval 1 The segment is in good shape.
1137 NET_CHECK_SIGNATURE (Nbuf
, NET_BUF_SIGNATURE
);
1139 Seg
= TCPSEG_NETBUF (Nbuf
);
1140 Len
= Nbuf
->TotalSize
;
1144 if (Head
->Flag
!= Seg
->Flag
) {
1148 Len
-= (Head
->HeadLen
<< 2);
1151 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
1155 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
1159 if (Seg
->Seq
+ Len
!= Seg
->End
) {
1168 Verify that all the segments in SndQue are in good shape.
1170 @param Head Pointer to the head node of the SndQue.
1172 @retval 0 At least one segment is broken.
1173 @retval 1 All segments in the specific queue are in good shape.
1185 if (IsListEmpty (Head
)) {
1189 // Initialize the Seq
1191 Entry
= Head
->ForwardLink
;
1192 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1193 Seq
= TCPSEG_NETBUF (Nbuf
)->Seq
;
1195 NET_LIST_FOR_EACH (Entry
, Head
) {
1196 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1198 if (TcpVerifySegment (Nbuf
) == 0) {
1203 // All the node in the SndQue should has:
1204 // SEG.SEQ = LAST_SEG.END
1206 if (Seq
!= TCPSEG_NETBUF (Nbuf
)->Seq
) {
1210 Seq
= TCPSEG_NETBUF (Nbuf
)->End
;