2 Misc support routines for tcp.
4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php<BR>
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Library/DevicePathLib.h>
20 LIST_ENTRY mTcpRunQue
= {
25 LIST_ENTRY mTcpListenQue
= {
30 TCP_SEQNO mTcpGlobalIss
= 0x4d7e980b;
32 CHAR16
*mTcpStateName
[] = {
48 Initialize the Tcb local related members.
50 @param Tcb Pointer to the TCP_CB of this TCP instance.
59 // Compute the checksum of the fixed parts of pseudo header
61 Tcb
->HeadSum
= NetPseudoHeadChecksum (
68 Tcb
->Iss
= TcpGetIss ();
69 Tcb
->SndUna
= Tcb
->Iss
;
70 Tcb
->SndNxt
= Tcb
->Iss
;
72 Tcb
->SndWl2
= Tcb
->Iss
;
75 Tcb
->RcvWnd
= GET_RCV_BUFFSIZE (Tcb
->Sk
);
78 // First window size is never scaled
81 Tcb
->RetxmitSeqMax
= 0;
83 Tcb
->ProbeTimerOn
= FALSE
;
88 Initialize the peer related members.
90 @param Tcb Pointer to the TCP_CB of this TCP instance.
91 @param Seg Pointer to the segment that contains the peer's
93 @param Opt Pointer to the options announced by the peer.
105 ASSERT ((Tcb
!= NULL
) && (Seg
!= NULL
) && (Opt
!= NULL
));
106 ASSERT (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
));
108 Tcb
->SndWnd
= Seg
->Wnd
;
109 Tcb
->SndWndMax
= Tcb
->SndWnd
;
110 Tcb
->SndWl1
= Seg
->Seq
;
112 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
113 Tcb
->SndWl2
= Seg
->Ack
;
115 Tcb
->SndWl2
= Tcb
->Iss
+ 1;
118 if (TCP_FLG_ON (Opt
->Flag
, TCP_OPTION_RCVD_MSS
)) {
119 Tcb
->SndMss
= (UINT16
) MAX (64, Opt
->Mss
);
121 RcvMss
= TcpGetRcvMss (Tcb
->Sk
);
122 if (Tcb
->SndMss
> RcvMss
) {
123 Tcb
->SndMss
= RcvMss
;
128 // One end doesn't support MSS option, use default.
133 Tcb
->CWnd
= Tcb
->SndMss
;
136 Tcb
->RcvNxt
= Tcb
->Irs
+ 1;
138 Tcb
->RcvWl2
= Tcb
->RcvNxt
;
140 if (TCP_FLG_ON (Opt
->Flag
, TCP_OPTION_RCVD_WS
) &&
141 !TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_NO_WS
)) {
143 Tcb
->SndWndScale
= Opt
->WndScale
;
145 Tcb
->RcvWndScale
= TcpComputeScale (Tcb
);
146 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_WS
);
150 // One end doesn't support window scale option. use zero.
152 Tcb
->RcvWndScale
= 0;
155 if (TCP_FLG_ON (Opt
->Flag
, TCP_OPTION_RCVD_TS
) &&
156 !TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_NO_TS
)) {
158 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_TS
);
159 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_TS
);
161 Tcb
->TsRecent
= Opt
->TSVal
;
164 // Compute the effective SndMss per RFC1122
165 // section 4.2.2.6. If timestamp option is
166 // enabled, it will always occupy 12 bytes.
168 Tcb
->SndMss
-= TCP_OPTION_TS_ALIGNED_LEN
;
174 Locate a listen TCB that matchs the Local and Remote.
176 @param Local Pointer to the local (IP, Port).
177 @param Remote Pointer to the remote (IP, Port).
179 @return Pointer to the TCP_CB with the least number of wildcard,
180 if NULL no match is found.
198 NET_LIST_FOR_EACH (Entry
, &mTcpListenQue
) {
199 Node
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
201 if ((Local
->Port
!= Node
->LocalEnd
.Port
) ||
202 !TCP_PEER_MATCH (Remote
, &Node
->RemoteEnd
) ||
203 !TCP_PEER_MATCH (Local
, &Node
->LocalEnd
)) {
209 // Compute the number of wildcard
212 if (Node
->RemoteEnd
.Ip
== 0) {
216 if (Node
->RemoteEnd
.Port
== 0) {
220 if (Node
->LocalEnd
.Ip
== 0) {
239 Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.
241 @param Addr Pointer to the IP address needs to match.
242 @param Port The port number needs to match.
244 @return The Tcb which matches the <Addr Port> paire exists or not.
249 IN EFI_IPv4_ADDRESS
*Addr
,
253 TCP_PORTNO LocalPort
;
257 ASSERT ((Addr
!= NULL
) && (Port
!= 0));
259 LocalPort
= HTONS (Port
);
261 NET_LIST_FOR_EACH (Entry
, &mTcpListenQue
) {
262 Tcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
264 if (EFI_IP4_EQUAL (Addr
, &Tcb
->LocalEnd
.Ip
) &&
265 (LocalPort
== Tcb
->LocalEnd
.Port
)) {
271 NET_LIST_FOR_EACH (Entry
, &mTcpRunQue
) {
272 Tcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
274 if (EFI_IP4_EQUAL (Addr
, &Tcb
->LocalEnd
.Ip
) &&
275 (LocalPort
== Tcb
->LocalEnd
.Port
)) {
286 Locate the TCP_CB related to the socket pair.
288 @param LocalPort The local port number.
289 @param LocalIp The local IP address.
290 @param RemotePort The remote port number.
291 @param RemoteIp The remote IP address.
292 @param Syn Whether to search the listen sockets, if TRUE, the
293 listen sockets are searched.
295 @return Pointer to the related TCP_CB, if NULL no match is found.
300 IN TCP_PORTNO LocalPort
,
302 IN TCP_PORTNO RemotePort
,
312 Local
.Port
= LocalPort
;
315 Remote
.Port
= RemotePort
;
316 Remote
.Ip
= RemoteIp
;
319 // First check for exact match.
321 NET_LIST_FOR_EACH (Entry
, &mTcpRunQue
) {
322 Tcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
324 if (TCP_PEER_EQUAL (&Remote
, &Tcb
->RemoteEnd
) &&
325 TCP_PEER_EQUAL (&Local
, &Tcb
->LocalEnd
)) {
327 RemoveEntryList (&Tcb
->List
);
328 InsertHeadList (&mTcpRunQue
, &Tcb
->List
);
335 // Only check listen queue when SYN flag is on
338 return TcpLocateListenTcb (&Local
, &Remote
);
346 Insert a Tcb into the proper queue.
348 @param Tcb Pointer to the TCP_CB to be inserted.
350 @retval 0 The Tcb is inserted successfully.
351 @retval -1 Error condition occurred.
365 ((Tcb
->State
== TCP_LISTEN
) ||
366 (Tcb
->State
== TCP_SYN_SENT
) ||
367 (Tcb
->State
== TCP_SYN_RCVD
) ||
368 (Tcb
->State
== TCP_CLOSED
))
371 if (Tcb
->LocalEnd
.Port
== 0) {
377 if (Tcb
->State
== TCP_LISTEN
) {
378 Head
= &mTcpListenQue
;
382 // Check that Tcb isn't already on the list.
384 NET_LIST_FOR_EACH (Entry
, Head
) {
385 Node
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
387 if (TCP_PEER_EQUAL (&Tcb
->LocalEnd
, &Node
->LocalEnd
) &&
388 TCP_PEER_EQUAL (&Tcb
->RemoteEnd
, &Node
->RemoteEnd
)) {
394 InsertHeadList (Head
, &Tcb
->List
);
401 Clone a TCB_CB from Tcb.
403 @param Tcb Pointer to the TCP_CB to be cloned.
405 @return Pointer to the new cloned TCP_CB, if NULL error condition occurred.
415 Clone
= AllocatePool (sizeof (TCP_CB
));
422 CopyMem (Clone
, Tcb
, sizeof (TCP_CB
));
425 // Increate the reference count of the shared IpInfo.
427 NET_GET_REF (Tcb
->IpInfo
);
429 InitializeListHead (&Clone
->List
);
430 InitializeListHead (&Clone
->SndQue
);
431 InitializeListHead (&Clone
->RcvQue
);
433 Clone
->Sk
= SockClone (Tcb
->Sk
);
434 if (Clone
->Sk
== NULL
) {
435 DEBUG ((EFI_D_ERROR
, "TcpCloneTcb: failed to clone a sock\n"));
440 ((TCP4_PROTO_DATA
*) (Clone
->Sk
->ProtoReserved
))->TcpPcb
= Clone
;
447 Compute an ISS to be used by a new connection.
449 @return The result ISS.
457 mTcpGlobalIss
+= 2048;
458 return mTcpGlobalIss
;
465 @param Sock Pointer to the socket to get mss
467 @return The mss size.
475 EFI_IP4_MODE_DATA Ip4Mode
;
476 TCP4_PROTO_DATA
*TcpProto
;
477 EFI_IP4_PROTOCOL
*Ip
;
479 ASSERT (Sock
!= NULL
);
481 TcpProto
= (TCP4_PROTO_DATA
*) Sock
->ProtoReserved
;
482 Ip
= TcpProto
->TcpService
->IpIo
->Ip
.Ip4
;
485 Ip
->GetModeData (Ip
, &Ip4Mode
, NULL
, NULL
);
487 return (UINT16
) (Ip4Mode
.MaxPacketSize
- sizeof (TCP_HEAD
));
494 @param Tcb Pointer to the TCP_CB of this TCP instance.
495 @param State The state to be set.
504 ASSERT (Tcb
->State
< (sizeof (mTcpStateName
) / sizeof (CHAR16
*)));
505 ASSERT (State
< (sizeof (mTcpStateName
) / sizeof (CHAR16
*)));
509 "Tcb (%p) state %s --> %s\n",
511 mTcpStateName
[Tcb
->State
],
512 mTcpStateName
[State
])
518 case TCP_ESTABLISHED
:
520 SockConnEstablished (Tcb
->Sk
);
522 if (Tcb
->Parent
!= NULL
) {
524 // A new connection is accepted by a listening socket, install
527 TcpInstallDevicePath (Tcb
->Sk
);
534 SockConnClosed (Tcb
->Sk
);
544 Compute the TCP segment's checksum.
546 @param Nbuf Pointer to the buffer that contains the TCP
548 @param HeadSum The checksum value of the fixed part of pseudo
551 @return The checksum value.
562 Checksum
= NetbufChecksum (Nbuf
);
563 Checksum
= NetAddChecksum (Checksum
, HeadSum
);
565 Checksum
= NetAddChecksum (
567 HTONS ((UINT16
) Nbuf
->TotalSize
)
570 return (UINT16
) ~Checksum
;
574 Translate the information from the head of the received TCP
575 segment Nbuf contains and fill it into a TCP_SEG structure.
577 @param Tcb Pointer to the TCP_CB of this TCP instance.
578 @param Nbuf Pointer to the buffer contains the TCP segment.
580 @return Pointer to the TCP_SEG that contains the translated TCP head information.
592 Seg
= TCPSEG_NETBUF (Nbuf
);
593 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
594 ASSERT (Head
!= NULL
);
597 Seg
->Seq
= NTOHL (Head
->Seq
);
598 Seg
->Ack
= NTOHL (Head
->Ack
);
599 Seg
->End
= Seg
->Seq
+ (Nbuf
->TotalSize
- (Head
->HeadLen
<< 2));
601 Seg
->Urg
= NTOHS (Head
->Urg
);
602 Seg
->Wnd
= (NTOHS (Head
->Wnd
) << Tcb
->SndWndScale
);
603 Seg
->Flag
= Head
->Flag
;
606 // SYN and FIN flag occupy one sequence space each.
608 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
610 // RFC requires that initial window not be scaled
612 Seg
->Wnd
= NTOHS (Head
->Wnd
);
616 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
625 Reset the connection related with Tcb.
627 @param Tcb Pointer to the TCP_CB of the connection to be
639 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
645 Nhead
= (TCP_HEAD
*) NetbufAllocSpace (
651 ASSERT (Nhead
!= NULL
);
655 Nhead
->Flag
= TCP_FLG_RST
;
656 Nhead
->Seq
= HTONL (Tcb
->SndNxt
);
657 Nhead
->Ack
= HTONL (Tcb
->RcvNxt
);
658 Nhead
->SrcPort
= Tcb
->LocalEnd
.Port
;
659 Nhead
->DstPort
= Tcb
->RemoteEnd
.Port
;
660 Nhead
->HeadLen
= (UINT8
) (sizeof (TCP_HEAD
) >> 2);
662 Nhead
->Wnd
= HTONS (0xFFFF);
665 Nhead
->Checksum
= TcpChecksum (Nbuf
, Tcb
->HeadSum
);
667 TcpSendIpPacket (Tcb
, Nbuf
, Tcb
->LocalEnd
.Ip
, Tcb
->RemoteEnd
.Ip
);
674 Initialize an active connection.
676 @param Tcb Pointer to the TCP_CB that wants to initiate a
685 TcpInitTcbLocal (Tcb
);
686 TcpSetState (Tcb
, TCP_SYN_SENT
);
688 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
689 TcpToSendData (Tcb
, 1);
694 Initiate the connection close procedure, called when
695 applications want to close the connection.
697 @param Tcb Pointer to the TCP_CB of this TCP instance.
705 ASSERT (Tcb
!= NULL
);
707 if (!IsListEmpty (&Tcb
->RcvQue
) || GET_RCV_DATASIZE (Tcb
->Sk
) != 0) {
709 DEBUG ((EFI_D_WARN
, "TcpOnAppClose: connection reset "
710 "because data is lost for TCB %p\n", Tcb
));
712 TcpResetConnection (Tcb
);
717 switch (Tcb
->State
) {
721 TcpSetState (Tcb
, TCP_CLOSED
);
725 case TCP_ESTABLISHED
:
726 TcpSetState (Tcb
, TCP_FIN_WAIT_1
);
730 TcpSetState (Tcb
, TCP_LAST_ACK
);
736 TcpToSendData (Tcb
, 1);
741 Check whether the application's newly delivered data can be sent out.
743 @param Tcb Pointer to the TCP_CB of this TCP instance.
745 @retval 0 Whether the data is sent out or is buffered for
747 @retval -1 The Tcb is not in a state that data is permitted to
757 switch (Tcb
->State
) {
768 case TCP_ESTABLISHED
:
770 TcpToSendData (Tcb
, 0);
789 Application has consumed some data, check whether
790 to send a window updata ack or a delayed ack.
792 @param Tcb Pointer to the TCP_CB of this TCP instance.
802 switch (Tcb
->State
) {
813 case TCP_ESTABLISHED
:
814 TcpOld
= TcpRcvWinOld (Tcb
);
815 if (TcpRcvWinNow (Tcb
) > TcpOld
) {
817 if (TcpOld
< Tcb
->RcvMss
) {
819 DEBUG ((EFI_D_NET
, "TcpOnAppConsume: send a window"
820 " update for a window closed Tcb %p\n", Tcb
));
823 } else if (Tcb
->DelayedAck
== 0) {
825 DEBUG ((EFI_D_NET
, "TcpOnAppConsume: scheduled a delayed"
826 " ACK to update window for Tcb %p\n", Tcb
));
851 Abort the connection by sending a reset segment, called
852 when the application wants to abort the connection.
854 @param Tcb Pointer to the TCP_CB of the TCP instance.
862 DEBUG ((EFI_D_WARN
, "TcpOnAppAbort: connection reset "
863 "issued by application for TCB %p\n", Tcb
));
865 switch (Tcb
->State
) {
867 case TCP_ESTABLISHED
:
871 TcpResetConnection (Tcb
);
877 TcpSetState (Tcb
, TCP_CLOSED
);
881 Install the device path protocol on the TCP instance.
883 @param Sock Pointer to the socket representing the TCP instance.
885 @retval EFI_SUCCESS The device path protocol is installed.
886 @retval other Failed to install the device path protocol.
890 TcpInstallDevicePath (
894 TCP4_PROTO_DATA
*TcpProto
;
895 TCP4_SERVICE_DATA
*TcpService
;
897 IPv4_DEVICE_PATH Ip4DPathNode
;
899 TCP_PORTNO LocalPort
;
900 TCP_PORTNO RemotePort
;
902 TcpProto
= (TCP4_PROTO_DATA
*) Sock
->ProtoReserved
;
903 TcpService
= TcpProto
->TcpService
;
904 Tcb
= TcpProto
->TcpPcb
;
906 LocalPort
= NTOHS (Tcb
->LocalEnd
.Port
);
907 RemotePort
= NTOHS (Tcb
->RemoteEnd
.Port
);
908 NetLibCreateIPv4DPathNode (
910 TcpService
->ControllerHandle
,
919 IP4_COPY_ADDRESS (&Ip4DPathNode
.SubnetMask
, &Tcb
->SubnetMask
);
921 Sock
->DevicePath
= AppendDevicePathNode (
922 Sock
->ParentDevicePath
,
923 (EFI_DEVICE_PATH_PROTOCOL
*) &Ip4DPathNode
925 if (Sock
->DevicePath
== NULL
) {
926 return EFI_OUT_OF_RESOURCES
;
929 Status
= gBS
->InstallProtocolInterface (
931 &gEfiDevicePathProtocolGuid
,
932 EFI_NATIVE_INTERFACE
,
935 if (EFI_ERROR (Status
)) {
936 FreePool (Sock
->DevicePath
);