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 Misc support routines for tcp.
26 NET_LIST_ENTRY mTcpRunQue
= {
31 NET_LIST_ENTRY mTcpListenQue
= {
36 TCP_SEQNO mTcpGlobalIss
= 0x4d7e980b;
38 STATIC CHAR16
*mTcpStateName
[] = {
54 Initialize the Tcb local related members.
56 @param Tcb Pointer to the TCP_CB of this TCP instance.
67 // Compute the checksum of the fixed parts of pseudo header
69 Tcb
->HeadSum
= NetPseudoHeadChecksum (
76 Tcb
->Iss
= TcpGetIss ();
77 Tcb
->SndUna
= Tcb
->Iss
;
78 Tcb
->SndNxt
= Tcb
->Iss
;
80 Tcb
->SndWl2
= Tcb
->Iss
;
83 Tcb
->RcvWnd
= GET_RCV_BUFFSIZE (Tcb
->Sk
);
86 // Fisrt window size is never scaled
93 Initialize the peer related members.
95 @param Tcb Pointer to the TCP_CB of this TCP instance.
96 @param Seg Pointer to the segment that contains the peer's
98 @param Opt Pointer to the options announced by the peer.
112 ASSERT (Tcb
&& Seg
&& Opt
);
113 ASSERT (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
));
115 Tcb
->SndWnd
= Seg
->Wnd
;
116 Tcb
->SndWndMax
= Tcb
->SndWnd
;
117 Tcb
->SndWl1
= Seg
->Seq
;
119 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
120 Tcb
->SndWl2
= Seg
->Ack
;
122 Tcb
->SndWl2
= Tcb
->Iss
+ 1;
125 if (TCP_FLG_ON (Opt
->Flag
, TCP_OPTION_RCVD_MSS
)) {
126 Tcb
->SndMss
= NET_MAX (64, Opt
->Mss
);
128 RcvMss
= TcpGetRcvMss (Tcb
->Sk
);
129 if (Tcb
->SndMss
> RcvMss
) {
130 Tcb
->SndMss
= RcvMss
;
135 // One end doesn't support MSS option, use default.
140 Tcb
->CWnd
= Tcb
->SndMss
;
143 Tcb
->RcvNxt
= Tcb
->Irs
+ 1;
145 Tcb
->RcvWl2
= Tcb
->RcvNxt
;
147 if (TCP_FLG_ON (Opt
->Flag
, TCP_OPTION_RCVD_WS
) &&
148 !TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_NO_WS
)) {
150 Tcb
->SndWndScale
= Opt
->WndScale
;
152 Tcb
->RcvWndScale
= TcpComputeScale (Tcb
);
153 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_WS
);
157 // One end doesn't support window scale option. use zero.
159 Tcb
->RcvWndScale
= 0;
162 if (TCP_FLG_ON (Opt
->Flag
, TCP_OPTION_RCVD_TS
) &&
163 !TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_NO_TS
)) {
165 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_TS
);
166 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_TS
);
169 // Compute the effective SndMss per RFC1122
170 // section 4.2.2.6. If timestamp option is
171 // enabled, it will always occupy 12 bytes.
173 Tcb
->SndMss
-= TCP_OPTION_TS_ALIGNED_LEN
;
179 Locate a listen TCB that matchs the Local and Remote.
181 @param Local Pointer to the local (IP, Port).
182 @param Remote Pointer to the remote (IP, Port).
184 @return Pointer to the TCP_CB with the least number of wildcard, if NULL no match is found.
194 NET_LIST_ENTRY
*Entry
;
203 NET_LIST_FOR_EACH (Entry
, &mTcpListenQue
) {
204 Node
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
206 if ((Local
->Port
!= Node
->LocalEnd
.Port
) ||
207 !TCP_PEER_MATCH (Remote
, &Node
->RemoteEnd
) ||
208 !TCP_PEER_MATCH (Local
, &Node
->LocalEnd
)
215 // Compute the number of wildcard
218 if (Node
->RemoteEnd
.Ip
== 0) {
222 if (Node
->RemoteEnd
.Port
== 0) {
226 if (Node
->LocalEnd
.Ip
== 0) {
245 Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.
247 @param Addr Pointer to the IP address needs to match.
248 @param Port The port number needs to match.
250 @return The Tcb which matches the <Addr Port> paire exists or not.
255 IN EFI_IPv4_ADDRESS
*Addr
,
259 TCP_PORTNO LocalPort
;
260 NET_LIST_ENTRY
*Entry
;
263 ASSERT ((Addr
!= NULL
) && (Port
!= 0));
265 LocalPort
= HTONS (Port
);
267 NET_LIST_FOR_EACH (Entry
, &mTcpListenQue
) {
268 Tcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
270 if ((EFI_IP4 (*Addr
) == Tcb
->LocalEnd
.Ip
) &&
271 (LocalPort
== Tcb
->LocalEnd
.Port
)) {
277 NET_LIST_FOR_EACH (Entry
, &mTcpRunQue
) {
278 Tcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
280 if (((EFI_IP4 (*Addr
) == Tcb
->LocalEnd
.Ip
)) &&
281 (LocalPort
== Tcb
->LocalEnd
.Port
)) {
292 Locate the TCP_CB related to the socket pair.
294 @param LocalPort The local port number.
295 @param LocalIp The local IP address.
296 @param RemotePort The remote port number.
297 @param RemoteIp The remote IP address.
298 @param Syn Whether to search the listen sockets, if TRUE, the
299 listen sockets are searched.
301 @return Pointer to the related TCP_CB, if NULL no match is found.
306 IN TCP_PORTNO LocalPort
,
308 IN TCP_PORTNO RemotePort
,
315 NET_LIST_ENTRY
*Entry
;
318 Local
.Port
= LocalPort
;
321 Remote
.Port
= RemotePort
;
322 Remote
.Ip
= RemoteIp
;
325 // First check for exact match.
327 NET_LIST_FOR_EACH (Entry
, &mTcpRunQue
) {
328 Tcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
330 if (TCP_PEER_EQUAL (&Remote
, &Tcb
->RemoteEnd
) &&
331 TCP_PEER_EQUAL (&Local
, &Tcb
->LocalEnd
)) {
333 NetListRemoveEntry (&Tcb
->List
);
334 NetListInsertHead (&mTcpRunQue
, &Tcb
->List
);
341 // Only check listen queue when SYN flag is on
344 return TcpLocateListenTcb (&Local
, &Remote
);
352 Insert a Tcb into the proper queue.
354 @param Tcb Pointer to the TCP_CB to be inserted.
356 @retval 0 The Tcb is inserted successfully.
357 @retval -1 Error condition occurred.
365 NET_LIST_ENTRY
*Entry
;
366 NET_LIST_ENTRY
*Head
;
368 TCP4_PROTO_DATA
*TcpProto
;
373 (Tcb
->State
== TCP_LISTEN
) ||
374 (Tcb
->State
== TCP_SYN_SENT
) ||
375 (Tcb
->State
== TCP_SYN_RCVD
) ||
376 (Tcb
->State
== TCP_CLOSED
)
380 if (Tcb
->LocalEnd
.Port
== 0) {
386 if (Tcb
->State
== TCP_LISTEN
) {
387 Head
= &mTcpListenQue
;
391 // Check that Tcb isn't already on the list.
393 NET_LIST_FOR_EACH (Entry
, Head
) {
394 Node
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
396 if (TCP_PEER_EQUAL (&Tcb
->LocalEnd
, &Node
->LocalEnd
) &&
397 TCP_PEER_EQUAL (&Tcb
->RemoteEnd
, &Node
->RemoteEnd
)) {
403 NetListInsertHead (Head
, &Tcb
->List
);
405 TcpProto
= (TCP4_PROTO_DATA
*) Tcb
->Sk
->ProtoReserved
;
406 TcpSetVariableData (TcpProto
->TcpService
);
413 Clone a TCP_CB from Tcb.
415 @param Tcb Pointer to the TCP_CB to be cloned.
417 @return Pointer to the new cloned TCP_CB, if NULL error condition occurred.
427 Clone
= NetAllocatePool (sizeof (TCP_CB
));
434 NetCopyMem (Clone
, Tcb
, sizeof (TCP_CB
));
437 // Increate the reference count of the shared IpInfo.
439 NET_GET_REF (Tcb
->IpInfo
);
441 NetListInit (&Clone
->List
);
442 NetListInit (&Clone
->SndQue
);
443 NetListInit (&Clone
->RcvQue
);
445 Clone
->Sk
= SockClone (Tcb
->Sk
);
446 if (Clone
->Sk
== NULL
) {
447 TCP4_DEBUG_ERROR (("TcpCloneTcb: failed to clone a sock\n"));
452 ((TCP4_PROTO_DATA
*) (Clone
->Sk
->ProtoReserved
))->TcpPcb
= Clone
;
459 Compute an ISS to be used by a new connection.
463 @return The result ISS.
471 mTcpGlobalIss
+= 2048;
472 return mTcpGlobalIss
;
481 @return The mss size.
489 EFI_SIMPLE_NETWORK_MODE SnpMode
;
490 TCP4_PROTO_DATA
*TcpProto
;
491 EFI_IP4_PROTOCOL
*Ip
;
495 TcpProto
= (TCP4_PROTO_DATA
*) Sock
->ProtoReserved
;
496 Ip
= TcpProto
->TcpService
->IpIo
->Ip
;
499 Ip
->GetModeData (Ip
, NULL
, NULL
, &SnpMode
);
501 return (UINT16
) (SnpMode
.MaxPacketSize
- 40);
508 @param Tcb Pointer to the TCP_CB of this TCP instance.
509 @param State The state to be set.
521 ("Tcb (%x) state %s --> %s\n",
523 mTcpStateName
[Tcb
->State
],
524 mTcpStateName
[State
])
530 case TCP_ESTABLISHED
:
532 SockConnEstablished (Tcb
->Sk
);
537 SockConnClosed (Tcb
->Sk
);
545 Compute the TCP segment's checksum.
547 @param Nbuf Pointer to the buffer that contains the TCP
549 @param HeadSum The checksum value of the fixed part of pseudo
552 @return The checksum value.
563 Checksum
= NetbufChecksum (Nbuf
);
564 Checksum
= NetAddChecksum (Checksum
, HeadSum
);
566 Checksum
= NetAddChecksum (
568 HTONS ((UINT16
) Nbuf
->TotalSize
)
576 Translate the information from the head of the received TCP
577 segment Nbuf contains and fill it into a TCP_SEG structure.
579 @param Tcb Pointer to the TCP_CB of this TCP instance.
580 @param Nbuf Pointer to the buffer contains the TCP segment.
582 @return Pointer to the TCP_SEG that contains the translated TCP head information.
594 Seg
= TCPSEG_NETBUF (Nbuf
);
595 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
598 Seg
->Seq
= NTOHL (Head
->Seq
);
599 Seg
->Ack
= NTOHL (Head
->Ack
);
600 Seg
->End
= Seg
->Seq
+ (Nbuf
->TotalSize
- (Head
->HeadLen
<< 2));
602 Seg
->Urg
= NTOHS (Head
->Urg
);
603 Seg
->Wnd
= (NTOHS (Head
->Wnd
) << Tcb
->SndWndScale
);
604 Seg
->Flag
= Head
->Flag
;
607 // SYN and FIN flag occupy one sequence space each.
609 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
611 // RFC requires that initial window not be scaled
613 Seg
->Wnd
= NTOHS (Head
->Wnd
);
617 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
626 Reset the connection related with Tcb.
628 @param Tcb Pointer to the TCP_CB of the connection to be
642 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
648 Nhead
= (TCP_HEAD
*) NetbufAllocSpace (
654 ASSERT (Nhead
!= NULL
);
658 Nhead
->Flag
= TCP_FLG_RST
;
659 Nhead
->Seq
= HTONL (Tcb
->SndNxt
);
660 Nhead
->Ack
= HTONL (Tcb
->RcvNxt
);
661 Nhead
->SrcPort
= Tcb
->LocalEnd
.Port
;
662 Nhead
->DstPort
= Tcb
->RemoteEnd
.Port
;
663 Nhead
->HeadLen
= (sizeof (TCP_HEAD
) >> 2);
665 Nhead
->Wnd
= HTONS (0xFFFF);
668 Nhead
->Checksum
= TcpChecksum (Nbuf
, Tcb
->HeadSum
);
670 TcpSendIpPacket (Tcb
, Nbuf
, Tcb
->LocalEnd
.Ip
, Tcb
->RemoteEnd
.Ip
);
677 Initialize an active connection,
679 @param Tcb Pointer to the TCP_CB that wants to initiate a
690 TcpInitTcbLocal (Tcb
);
691 TcpSetState (Tcb
, TCP_SYN_SENT
);
693 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
694 TcpToSendData (Tcb
, 1);
699 Initiate the connection close procedure, called when
700 applications want to close the connection.
702 @param Tcb Pointer to the TCP_CB of this TCP instance.
714 if (!NetListIsEmpty (&Tcb
->RcvQue
) || GET_RCV_DATASIZE (Tcb
->Sk
)) {
716 TCP4_DEBUG_WARN (("TcpOnAppClose: connection reset "
717 "because data is lost for TCB %x\n", Tcb
));
719 TcpResetConnection (Tcb
);
724 switch (Tcb
->State
) {
728 TcpSetState (Tcb
, TCP_CLOSED
);
732 case TCP_ESTABLISHED
:
733 TcpSetState (Tcb
, TCP_FIN_WAIT_1
);
737 TcpSetState (Tcb
, TCP_LAST_ACK
);
741 TcpToSendData (Tcb
, 1);
746 Check whether the application's newly delivered data
749 @param Tcb Pointer to the TCP_CB of this TCP instance.
751 @retval 0 Whether the data is sent out or is buffered for
753 @retval -1 The Tcb is not in a state that data is permitted to
763 switch (Tcb
->State
) {
777 case TCP_ESTABLISHED
:
779 TcpToSendData (Tcb
, 0);
797 Application has consumed some data, check whether
798 to send a window updata ack or a delayed ack.
800 @param Tcb Pointer to the TCP_CB of this TCP instance.
810 switch (Tcb
->State
) {
824 case TCP_ESTABLISHED
:
825 if (TcpRcvWinNow (Tcb
) > TcpRcvWinOld (Tcb
)) {
827 if (TcpRcvWinOld (Tcb
) < Tcb
->RcvMss
) {
829 TCP4_DEBUG_TRACE (("TcpOnAppConsume: send a window"
830 " update for a window closed Tcb(%x)\n", Tcb
));
833 } else if (Tcb
->DelayedAck
== 0) {
835 TCP4_DEBUG_TRACE (("TcpOnAppConsume: scheduled a delayed"
836 " ACK to update window for Tcb(%x)\n", Tcb
));
862 Abort the connection by sending a reset segment, called
863 when the application wants to abort the connection.
865 @param Tcb Pointer to the TCP_CB of the TCP instance.
875 TCP4_DEBUG_WARN (("TcpOnAppAbort: connection reset "
876 "issued by application for TCB %x\n", Tcb
));
878 switch (Tcb
->State
) {
880 case TCP_ESTABLISHED
:
884 TcpResetConnection (Tcb
);
888 TcpSetState (Tcb
, TCP_CLOSED
);
893 Set the Tdp4 variable data.
895 @param Tcp4Service Tcp4 service data.
897 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.
898 @retval other Set variable failed.
903 IN TCP4_SERVICE_DATA
*Tcp4Service
906 UINT32 NumConfiguredInstance
;
907 NET_LIST_ENTRY
*Entry
;
909 TCP4_PROTO_DATA
*TcpProto
;
910 UINTN VariableDataSize
;
911 EFI_TCP4_VARIABLE_DATA
*Tcp4VariableData
;
912 EFI_TCP4_SERVICE_POINT
*Tcp4ServicePoint
;
913 CHAR16
*NewMacString
;
916 NumConfiguredInstance
= 0;
919 // Go through the running queue to count the instances.
921 NET_LIST_FOR_EACH (Entry
, &mTcpRunQue
) {
922 TcpPcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
924 TcpProto
= (TCP4_PROTO_DATA
*) TcpPcb
->Sk
->ProtoReserved
;
926 if (TcpProto
->TcpService
== Tcp4Service
) {
928 // This tcp instance belongs to the Tcp4Service.
930 NumConfiguredInstance
++;
935 // Go through the listening queue to count the instances.
937 NET_LIST_FOR_EACH (Entry
, &mTcpListenQue
) {
938 TcpPcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
940 TcpProto
= (TCP4_PROTO_DATA
*) TcpPcb
->Sk
->ProtoReserved
;
942 if (TcpProto
->TcpService
== Tcp4Service
) {
944 // This tcp instance belongs to the Tcp4Service.
946 NumConfiguredInstance
++;
951 // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,
952 // we should add extra buffer for the service points only if the number of configured
953 // children is more than 1.
955 VariableDataSize
= sizeof (EFI_TCP4_VARIABLE_DATA
);
957 if (NumConfiguredInstance
> 1) {
958 VariableDataSize
+= sizeof (EFI_TCP4_SERVICE_POINT
) * (NumConfiguredInstance
- 1);
961 Tcp4VariableData
= NetAllocatePool (VariableDataSize
);
962 if (Tcp4VariableData
== NULL
) {
963 return EFI_OUT_OF_RESOURCES
;
966 Tcp4VariableData
->DriverHandle
= Tcp4Service
->DriverBindingHandle
;
967 Tcp4VariableData
->ServiceCount
= NumConfiguredInstance
;
969 Tcp4ServicePoint
= &Tcp4VariableData
->Services
[0];
972 // Go through the running queue to fill the service points.
974 NET_LIST_FOR_EACH (Entry
, &mTcpRunQue
) {
975 TcpPcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
977 TcpProto
= (TCP4_PROTO_DATA
*) TcpPcb
->Sk
->ProtoReserved
;
979 if (TcpProto
->TcpService
== Tcp4Service
) {
981 // This tcp instance belongs to the Tcp4Service.
983 Tcp4ServicePoint
->InstanceHandle
= TcpPcb
->Sk
->SockHandle
;
984 EFI_IP4 (Tcp4ServicePoint
->LocalAddress
) = TcpPcb
->LocalEnd
.Ip
;
985 Tcp4ServicePoint
->LocalPort
= NTOHS (TcpPcb
->LocalEnd
.Port
);
986 EFI_IP4 (Tcp4ServicePoint
->RemoteAddress
) = TcpPcb
->RemoteEnd
.Ip
;
987 Tcp4ServicePoint
->RemotePort
= NTOHS (TcpPcb
->RemoteEnd
.Port
);
994 // Go through the listening queue to fill the service points.
996 NET_LIST_FOR_EACH (Entry
, &mTcpListenQue
) {
997 TcpPcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
999 TcpProto
= (TCP4_PROTO_DATA
*) TcpPcb
->Sk
->ProtoReserved
;
1001 if (TcpProto
->TcpService
== Tcp4Service
) {
1003 // This tcp instance belongs to the Tcp4Service.
1005 Tcp4ServicePoint
->InstanceHandle
= TcpPcb
->Sk
->SockHandle
;
1006 EFI_IP4 (Tcp4ServicePoint
->LocalAddress
) = TcpPcb
->LocalEnd
.Ip
;
1007 Tcp4ServicePoint
->LocalPort
= NTOHS (TcpPcb
->LocalEnd
.Port
);
1008 EFI_IP4 (Tcp4ServicePoint
->RemoteAddress
) = TcpPcb
->RemoteEnd
.Ip
;
1009 Tcp4ServicePoint
->RemotePort
= NTOHS (TcpPcb
->RemoteEnd
.Port
);
1016 // Get the mac string.
1018 Status
= NetLibGetMacString (
1019 Tcp4Service
->ControllerHandle
,
1020 Tcp4Service
->DriverBindingHandle
,
1023 if (EFI_ERROR (Status
)) {
1027 if (Tcp4Service
->MacString
!= NULL
) {
1029 // The variable is set already, we're going to update it.
1031 if (StrCmp (Tcp4Service
->MacString
, NewMacString
) != 0) {
1033 // The mac address is changed, delete the previous variable first.
1036 Tcp4Service
->MacString
,
1037 &gEfiTcp4ServiceBindingProtocolGuid
,
1038 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1044 NetFreePool (Tcp4Service
->MacString
);
1047 Tcp4Service
->MacString
= NewMacString
;
1049 Status
= gRT
->SetVariable (
1050 Tcp4Service
->MacString
,
1051 &gEfiTcp4ServiceBindingProtocolGuid
,
1052 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1054 (VOID
*) Tcp4VariableData
1059 NetFreePool (Tcp4VariableData
);
1066 Clear the variable and free the resource.
1068 @param Tcp4Service Tcp4 service data.
1074 TcpClearVariableData (
1075 IN TCP4_SERVICE_DATA
*Tcp4Service
1078 ASSERT (Tcp4Service
->MacString
!= NULL
);
1081 Tcp4Service
->MacString
,
1082 &gEfiTcp4ServiceBindingProtocolGuid
,
1083 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1088 NetFreePool (Tcp4Service
->MacString
);
1089 Tcp4Service
->MacString
= NULL
;