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
= (UINT16
) 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_EQUAL (*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_EQUAL (*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
)
571 return (UINT16
) ~Checksum
;
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.
811 switch (Tcb
->State
) {
825 case TCP_ESTABLISHED
:
826 TcpOld
= TcpRcvWinOld (Tcb
);
827 if (TcpRcvWinNow (Tcb
) > TcpOld
) {
829 if (TcpOld
< Tcb
->RcvMss
) {
831 TCP4_DEBUG_TRACE (("TcpOnAppConsume: send a window"
832 " update for a window closed Tcb(%x)\n", Tcb
));
835 } else if (Tcb
->DelayedAck
== 0) {
837 TCP4_DEBUG_TRACE (("TcpOnAppConsume: scheduled a delayed"
838 " ACK to update window for Tcb(%x)\n", Tcb
));
864 Abort the connection by sending a reset segment, called
865 when the application wants to abort the connection.
867 @param Tcb Pointer to the TCP_CB of the TCP instance.
877 TCP4_DEBUG_WARN (("TcpOnAppAbort: connection reset "
878 "issued by application for TCB %x\n", Tcb
));
880 switch (Tcb
->State
) {
882 case TCP_ESTABLISHED
:
886 TcpResetConnection (Tcb
);
890 TcpSetState (Tcb
, TCP_CLOSED
);
895 Set the Tdp4 variable data.
897 @param Tcp4Service Tcp4 service data.
899 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.
900 @retval other Set variable failed.
905 IN TCP4_SERVICE_DATA
*Tcp4Service
908 UINT32 NumConfiguredInstance
;
909 NET_LIST_ENTRY
*Entry
;
911 TCP4_PROTO_DATA
*TcpProto
;
912 UINTN VariableDataSize
;
913 EFI_TCP4_VARIABLE_DATA
*Tcp4VariableData
;
914 EFI_TCP4_SERVICE_POINT
*Tcp4ServicePoint
;
915 CHAR16
*NewMacString
;
918 NumConfiguredInstance
= 0;
921 // Go through the running queue to count the instances.
923 NET_LIST_FOR_EACH (Entry
, &mTcpRunQue
) {
924 TcpPcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
926 TcpProto
= (TCP4_PROTO_DATA
*) TcpPcb
->Sk
->ProtoReserved
;
928 if (TcpProto
->TcpService
== Tcp4Service
) {
930 // This tcp instance belongs to the Tcp4Service.
932 NumConfiguredInstance
++;
937 // Go through the listening queue to count the instances.
939 NET_LIST_FOR_EACH (Entry
, &mTcpListenQue
) {
940 TcpPcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
942 TcpProto
= (TCP4_PROTO_DATA
*) TcpPcb
->Sk
->ProtoReserved
;
944 if (TcpProto
->TcpService
== Tcp4Service
) {
946 // This tcp instance belongs to the Tcp4Service.
948 NumConfiguredInstance
++;
953 // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,
954 // we should add extra buffer for the service points only if the number of configured
955 // children is more than 1.
957 VariableDataSize
= sizeof (EFI_TCP4_VARIABLE_DATA
);
959 if (NumConfiguredInstance
> 1) {
960 VariableDataSize
+= sizeof (EFI_TCP4_SERVICE_POINT
) * (NumConfiguredInstance
- 1);
963 Tcp4VariableData
= NetAllocatePool (VariableDataSize
);
964 if (Tcp4VariableData
== NULL
) {
965 return EFI_OUT_OF_RESOURCES
;
968 Tcp4VariableData
->DriverHandle
= Tcp4Service
->DriverBindingHandle
;
969 Tcp4VariableData
->ServiceCount
= NumConfiguredInstance
;
971 Tcp4ServicePoint
= &Tcp4VariableData
->Services
[0];
974 // Go through the running queue to fill the service points.
976 NET_LIST_FOR_EACH (Entry
, &mTcpRunQue
) {
977 TcpPcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
979 TcpProto
= (TCP4_PROTO_DATA
*) TcpPcb
->Sk
->ProtoReserved
;
981 if (TcpProto
->TcpService
== Tcp4Service
) {
983 // This tcp instance belongs to the Tcp4Service.
985 Tcp4ServicePoint
->InstanceHandle
= TcpPcb
->Sk
->SockHandle
;
986 NetCopyMem (&Tcp4ServicePoint
->LocalAddress
, &TcpPcb
->LocalEnd
.Ip
, sizeof (EFI_IPv4_ADDRESS
));
987 Tcp4ServicePoint
->LocalPort
= NTOHS (TcpPcb
->LocalEnd
.Port
);
988 NetCopyMem (&Tcp4ServicePoint
->RemoteAddress
, &TcpPcb
->RemoteEnd
.Ip
, sizeof (EFI_IPv4_ADDRESS
));
989 Tcp4ServicePoint
->RemotePort
= NTOHS (TcpPcb
->RemoteEnd
.Port
);
996 // Go through the listening queue to fill the service points.
998 NET_LIST_FOR_EACH (Entry
, &mTcpListenQue
) {
999 TcpPcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
1001 TcpProto
= (TCP4_PROTO_DATA
*) TcpPcb
->Sk
->ProtoReserved
;
1003 if (TcpProto
->TcpService
== Tcp4Service
) {
1005 // This tcp instance belongs to the Tcp4Service.
1007 Tcp4ServicePoint
->InstanceHandle
= TcpPcb
->Sk
->SockHandle
;
1008 NetCopyMem (&Tcp4ServicePoint
->LocalAddress
, &TcpPcb
->LocalEnd
.Ip
, sizeof (EFI_IPv4_ADDRESS
));
1009 Tcp4ServicePoint
->LocalPort
= NTOHS (TcpPcb
->LocalEnd
.Port
);
1010 NetCopyMem (&Tcp4ServicePoint
->RemoteAddress
, &TcpPcb
->RemoteEnd
.Ip
, sizeof (EFI_IPv4_ADDRESS
));
1011 Tcp4ServicePoint
->RemotePort
= NTOHS (TcpPcb
->RemoteEnd
.Port
);
1018 // Get the mac string.
1020 Status
= NetLibGetMacString (
1021 Tcp4Service
->ControllerHandle
,
1022 Tcp4Service
->DriverBindingHandle
,
1025 if (EFI_ERROR (Status
)) {
1029 if (Tcp4Service
->MacString
!= NULL
) {
1031 // The variable is set already, we're going to update it.
1033 if (StrCmp (Tcp4Service
->MacString
, NewMacString
) != 0) {
1035 // The mac address is changed, delete the previous variable first.
1038 Tcp4Service
->MacString
,
1039 &gEfiTcp4ServiceBindingProtocolGuid
,
1040 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1046 NetFreePool (Tcp4Service
->MacString
);
1049 Tcp4Service
->MacString
= NewMacString
;
1051 Status
= gRT
->SetVariable (
1052 Tcp4Service
->MacString
,
1053 &gEfiTcp4ServiceBindingProtocolGuid
,
1054 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1056 (VOID
*) Tcp4VariableData
1061 NetFreePool (Tcp4VariableData
);
1068 Clear the variable and free the resource.
1070 @param Tcp4Service Tcp4 service data.
1076 TcpClearVariableData (
1077 IN TCP4_SERVICE_DATA
*Tcp4Service
1080 ASSERT (Tcp4Service
->MacString
!= NULL
);
1083 Tcp4Service
->MacString
,
1084 &gEfiTcp4ServiceBindingProtocolGuid
,
1085 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1090 NetFreePool (Tcp4Service
->MacString
);
1091 Tcp4Service
->MacString
= NULL
;