]>
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 STATIC 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.
135 // RFC requires that initial window not be scaled
139 Wnd
= GET_RCV_BUFFSIZE (Tcb
->Sk
);
142 Wnd
= TcpRcvWinNow (Tcb
);
147 Wnd
= NET_MIN (Wnd
>> Tcb
->RcvWndScale
, 0xffff);
148 return NTOHS ((UINT16
) Wnd
);
153 Get the maximum SndNxt.
155 @param Tcb Pointer to the TCP_CB of this TCP instance.
157 @return The sequence number of the maximum SndNxt.
165 NET_LIST_ENTRY
*Entry
;
168 if (NetListIsEmpty (&Tcb
->SndQue
)) {
172 Entry
= Tcb
->SndQue
.BackLink
;
173 Nbuf
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
175 ASSERT (TCP_SEQ_GEQ (TCPSEG_NETBUF (Nbuf
)->End
, Tcb
->SndNxt
));
176 return TCPSEG_NETBUF (Nbuf
)->End
;
181 Compute how much data to send.
183 @param Tcb Pointer to the TCP_CB of this TCP instance.
184 @param Force Whether to ignore the sender's SWS avoidance algorithm and send
187 @return The length of the data can be sent, if 0, no data can be sent.
206 // TCP should NOT send data beyond the send window
207 // and congestion window. The right edge of send
208 // window is defined as SND.WL2 + SND.WND. The right
209 // edge of congestion window is defined as SND.UNA +
213 Limit
= Tcb
->SndWl2
+ Tcb
->SndWnd
;
215 if (TCP_SEQ_GT (Limit
, Tcb
->SndUna
+ Tcb
->CWnd
)) {
217 Limit
= Tcb
->SndUna
+ Tcb
->CWnd
;
220 if (TCP_SEQ_GT (Limit
, Tcb
->SndNxt
)) {
221 Win
= TCP_SUB_SEQ (Limit
, Tcb
->SndNxt
);
225 // The data to send contains two parts: the data on the
226 // socket send queue, and the data on the TCB's send
227 // buffer. The later can be non-zero if the peer shrinks
228 // its advertised window.
230 Left
= GET_SND_DATASIZE (Sk
) +
231 TCP_SUB_SEQ (TcpGetMaxSndNxt (Tcb
), Tcb
->SndNxt
);
233 Len
= NET_MIN (Win
, Left
);
235 if (Len
> Tcb
->SndMss
) {
239 if (Force
|| (Len
== 0 && Left
== 0)) {
243 if (Len
== 0 && Left
!= 0) {
244 goto SetPersistTimer
;
248 // Sender's SWS avoidance: Don't send a small segment unless
249 // a)A full-sized segment can be sent,
250 // b)at least one-half of the maximum sized windows that
251 // the other end has ever advertised.
252 // c)It can send everything it has and either it isn't
253 // expecting an ACK or the Nagle algorithm is disabled.
255 if ((Len
== Tcb
->SndMss
) || (2 * Len
>= Tcb
->SndWndMax
)) {
261 ((Tcb
->SndNxt
== Tcb
->SndUna
) ||
262 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_NO_NAGLE
))) {
268 // RFC1122 suggests to set a timer when SWSA forbids TCP
269 // sending more data, and combine it with probe timer.
272 if (!TCP_TIMER_ON (Tcb
->EnabledTimer
, TCP_TIMER_REXMIT
)) {
275 ("TcpDataToSend: enter persistent state for TCB %x\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.
310 ASSERT (Nbuf
&& (Nbuf
->Tcp
== NULL
) && TcpVerifySegment (Nbuf
));
312 DataLen
= Nbuf
->TotalSize
;
314 Seg
= TCPSEG_NETBUF (Nbuf
);
315 Syn
= TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
);
319 Len
= TcpSynBuildOption (Tcb
, Nbuf
);
322 Len
= TcpBuildOption (Tcb
, Nbuf
);
325 ASSERT ((Len
% 4 == 0) && (Len
<= 40));
327 Len
+= sizeof (TCP_HEAD
);
329 Head
= (TCP_HEAD
*) NetbufAllocSpace (
335 ASSERT (Head
!= NULL
);
339 Head
->SrcPort
= Tcb
->LocalEnd
.Port
;
340 Head
->DstPort
= Tcb
->RemoteEnd
.Port
;
341 Head
->Seq
= NTOHL (Seg
->Seq
);
342 Head
->Ack
= NTOHL (Tcb
->RcvNxt
);
343 Head
->HeadLen
= (UINT8
) (Len
>> 2);
345 Head
->Wnd
= TcpComputeWnd (Tcb
, Syn
);
349 // Check whether to set the PSH flag.
351 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_PSH
);
354 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_PSH
) &&
355 TCP_SEQ_BETWEEN (Seg
->Seq
, Tcb
->SndPsh
, Seg
->End
)) {
357 TCP_SET_FLG (Seg
->Flag
, TCP_FLG_PSH
);
358 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_PSH
);
360 } else if ((Seg
->End
== Tcb
->SndNxt
) &&
361 (GET_SND_DATASIZE (Tcb
->Sk
) == 0)) {
363 TCP_SET_FLG (Seg
->Flag
, TCP_FLG_PSH
);
368 // Check whether to set the URG flag and the urgent pointer.
370 TCP_CLEAR_FLG (Seg
->Flag
, TCP_FLG_URG
);
372 if (TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
) &&
373 TCP_SEQ_LEQ (Seg
->Seq
, Tcb
->SndUp
)) {
375 TCP_SET_FLG (Seg
->Flag
, TCP_FLG_URG
);
377 if (TCP_SEQ_LT (Tcb
->SndUp
, Seg
->End
)) {
379 Seg
->Urg
= (UINT16
) TCP_SUB_SEQ (Tcb
->SndUp
, Seg
->Seq
);
382 Seg
->Urg
= (UINT16
) NET_MIN (
383 TCP_SUB_SEQ (Tcb
->SndUp
,
390 Head
->Flag
= Seg
->Flag
;
391 Head
->Urg
= NTOHS (Seg
->Urg
);
392 Head
->Checksum
= TcpChecksum (Nbuf
, Tcb
->HeadSum
);
395 // update the TCP session's control information
397 Tcb
->RcvWl2
= Tcb
->RcvNxt
;
399 Tcb
->RcvWnd
= NTOHS (Head
->Wnd
);
403 // clear delayedack flag
407 return TcpSendIpPacket (Tcb
, Nbuf
, Tcb
->LocalEnd
.Ip
, Tcb
->RemoteEnd
.Ip
);
412 Get a segment from the Tcb's SndQue.
414 @param Tcb Pointer to the TCP_CB of this TCP instance.
415 @param Seq The sequence number of the segment.
416 @param Len The maximum length of the segment.
418 @return Pointer to the segment, if NULL some error occurred.
422 TcpGetSegmentSndQue (
428 NET_LIST_ENTRY
*Head
;
439 ASSERT (Tcb
&& TCP_SEQ_LEQ (Seq
, Tcb
->SndNxt
) && (Len
> 0));
442 // Find the segment that contains the Seq.
449 NET_LIST_FOR_EACH (Cur
, Head
) {
450 Node
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
451 Seg
= TCPSEG_NETBUF (Node
);
453 if (TCP_SEQ_LT (Seq
, Seg
->End
) && TCP_SEQ_LEQ (Seg
->Seq
, Seq
)) {
459 ASSERT (Cur
!= Head
);
462 // Return the buffer if it can be returned without
465 if ((Seg
->Seq
== Seq
) &&
466 TCP_SEQ_LEQ (Seg
->End
, Seg
->Seq
+ Len
) &&
467 !NET_BUF_SHARED (Node
)) {
474 // Create a new buffer and copy data there.
476 Nbuf
= NetbufAlloc (Len
+ TCP_MAX_HEAD
);
482 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
487 if (TCP_SEQ_LT (Seq
+ Len
, Seg
->End
)) {
491 CopyLen
= TCP_SUB_SEQ (End
, Seq
);
492 Offset
= TCP_SUB_SEQ (Seq
, Seg
->Seq
);
495 // If SYN is set and out of the range, clear the flag.
496 // Becuase the sequence of the first byte is SEG.SEQ+1,
497 // adjust Offset by -1. If SYN is in the range, copy
500 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
502 if (TCP_SEQ_LT (Seg
->Seq
, Seq
)) {
504 TCP_CLEAR_FLG (Flag
, TCP_FLG_SYN
);
513 // If FIN is set and in the range, copy one byte less,
514 // and if it is out of the range, clear the flag.
516 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
518 if (Seg
->End
== End
) {
523 TCP_CLEAR_FLG (Flag
, TCP_FLG_FIN
);
527 ASSERT (CopyLen
>= 0);
530 // copy data to the segment
533 Data
= NetbufAllocSpace (Nbuf
, CopyLen
, NET_BUF_TAIL
);
536 if ((INT32
) NetbufCopy (Node
, Offset
, CopyLen
, Data
) != CopyLen
) {
541 NetCopyMem (TCPSEG_NETBUF (Nbuf
), Seg
, sizeof (TCP_SEG
));
543 TCPSEG_NETBUF (Nbuf
)->Seq
= Seq
;
544 TCPSEG_NETBUF (Nbuf
)->End
= End
;
545 TCPSEG_NETBUF (Nbuf
)->Flag
= Flag
;
556 Get a segment from the Tcb's socket buffer.
558 @param Tcb Pointer to the TCP_CB of this TCP instance.
559 @param Seq The sequence number of the segment.
560 @param Len The maximum length of the segment.
562 @return Pointer to the segment, if NULL some error occurred.
576 ASSERT (Tcb
&& Tcb
->Sk
);
578 Nbuf
= NetbufAlloc (Len
+ TCP_MAX_HEAD
);
581 TCP4_DEBUG_ERROR (("TcpGetSegmentSock: failed to allocate "
582 "a netbuf for TCB %x\n",Tcb
));
587 NetbufReserve (Nbuf
, TCP_MAX_HEAD
);
593 // copy data to the segment.
595 Data
= NetbufAllocSpace (Nbuf
, Len
, NET_BUF_TAIL
);
598 DataGet
= SockGetDataToSend (Tcb
->Sk
, 0, Len
, Data
);
603 TCPSEG_NETBUF (Nbuf
)->Seq
= Seq
;
604 TCPSEG_NETBUF (Nbuf
)->End
= Seq
+ Len
;
606 NetListInsertTail (&(Tcb
->SndQue
), &(Nbuf
->List
));
610 SockDataSent (Tcb
->Sk
, DataGet
);
618 Get a segment starting from sequence Seq of a maximum
621 @param Tcb Pointer to the TCP_CB of this TCP instance.
622 @param Seq The sequence number of the segment.
623 @param Len The maximum length of the segment.
625 @return Pointer to the segment, if NULL some error occurred.
640 // Compare the SndNxt with the max sequence number sent.
642 if ((Len
!= 0) && TCP_SEQ_LT (Seq
, TcpGetMaxSndNxt (Tcb
))) {
644 Nbuf
= TcpGetSegmentSndQue (Tcb
, Seq
, Len
);
647 Nbuf
= TcpGetSegmentSock (Tcb
, Seq
, Len
);
650 ASSERT (TcpVerifySegment (Nbuf
));
656 Retransmit the segment from sequence Seq.
658 @param Tcb Pointer to the TCP_CB of this TCP instance.
659 @param Seq The sequence number of the segment to be retransmitted.
661 @retval 0 Retransmission succeeded.
662 @retval -1 Error condition occurred.
675 // Compute the maxium length of retransmission. It is
676 // limited by three factors:
677 // 1. Less than SndMss
678 // 2. must in the current send window
679 // 3. will not change the boundaries of queued segments.
681 if (TCP_SEQ_LT (Tcb
->SndWl2
+ Tcb
->SndWnd
, Seq
)) {
682 TCP4_DEBUG_WARN (("TcpRetransmit: retransmission cancelled "
683 "because send window too small for TCB %x\n", Tcb
));
688 Len
= TCP_SUB_SEQ (Tcb
->SndWl2
+ Tcb
->SndWnd
, Seq
);
689 Len
= NET_MIN (Len
, Tcb
->SndMss
);
691 Nbuf
= TcpGetSegmentSndQue (Tcb
, Seq
, Len
);
696 ASSERT (TcpVerifySegment (Nbuf
));
698 if (TcpTransmitSegment (Tcb
, Nbuf
) != 0) {
703 // The retransmitted buffer may be on the SndQue,
704 // trim TCP head because all the buffer on SndQue
708 NetbufTrim (Nbuf
, (Nbuf
->Tcp
->HeadLen
<< 2), NET_BUF_HEAD
);
724 Check whether to send data/SYN/FIN and piggy back an ACK.
726 @param Tcb Pointer to the TCP_CB of this TCP instance.
727 @param Force Whether to ignore the sender's SWS avoidance algorithm and send
730 @return The number of bytes sent.
747 ASSERT (Tcb
&& Tcb
->Sk
&& (Tcb
->State
!= TCP_LISTEN
));
751 if ((Tcb
->State
== TCP_CLOSED
) ||
752 TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_FIN_SENT
)) {
759 // compute how much data can be sent
761 Len
= TcpDataToSend (Tcb
, Force
);
764 Flag
= mTcpOutFlag
[Tcb
->State
];
766 if (Flag
& TCP_FLG_SYN
) {
773 // only send a segment without data if SYN or
776 if ((Len
== 0) && !(Flag
& (TCP_FLG_SYN
| TCP_FLG_FIN
))) {
780 Nbuf
= TcpGetSegment (Tcb
, Seq
, Len
);
784 ("TcpToSendData: failed to get a segment for TCB %x\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 TCP4_DEBUG_TRACE (("TcpToSendData: send FIN "
813 "to peer for TCB %x 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 TCP4_DEBUG_WARN (("TcpToSendData: created a empty"
833 " segment for TCB %x, 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 TCP4_DEBUG_TRACE (("TcpToSendData: set RTT measure "
890 "sequence %d for TCB %x\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 TCP4_DEBUG_TRACE (("TcpToSendAck: scheduled a delayed"
1024 " ACK for TCB %x\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.
1185 IN NET_LIST_ENTRY
*Head
1188 NET_LIST_ENTRY
*Entry
;
1192 if (NetListIsEmpty (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
;