2 Misc support routines for TCP driver.
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 LIST_ENTRY mTcpRunQue
= {
23 LIST_ENTRY mTcpListenQue
= {
28 TCP_SEQNO mTcpGlobalIss
= TCP_BASE_ISS
;
30 CHAR16
*mTcpStateName
[] = {
46 Initialize the Tcb local related members.
48 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
57 // Compute the checksum of the fixed parts of pseudo header
59 if (Tcb
->Sk
->IpVersion
== IP_VERSION_4
) {
60 Tcb
->HeadSum
= NetPseudoHeadChecksum (
61 Tcb
->LocalEnd
.Ip
.Addr
[0],
62 Tcb
->RemoteEnd
.Ip
.Addr
[0],
67 Tcb
->HeadSum
= NetIp6PseudoHeadChecksum (
69 &Tcb
->RemoteEnd
.Ip
.v6
,
75 Tcb
->Iss
= TcpGetIss ();
76 Tcb
->SndUna
= Tcb
->Iss
;
77 Tcb
->SndNxt
= Tcb
->Iss
;
79 Tcb
->SndWl2
= Tcb
->Iss
;
82 Tcb
->RcvWnd
= GET_RCV_BUFFSIZE (Tcb
->Sk
);
85 // First window size is never scaled
89 Tcb
->ProbeTimerOn
= FALSE
;
93 Initialize the peer related members.
95 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
96 @param[in] Seg Pointer to the segment that contains the peer's intial info.
97 @param[in] Opt Pointer to the options announced by the peer.
109 ASSERT ((Tcb
!= NULL
) && (Seg
!= NULL
) && (Opt
!= NULL
));
110 ASSERT (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
));
112 Tcb
->SndWnd
= Seg
->Wnd
;
113 Tcb
->SndWndMax
= Tcb
->SndWnd
;
114 Tcb
->SndWl1
= Seg
->Seq
;
116 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_ACK
)) {
117 Tcb
->SndWl2
= Seg
->Ack
;
119 Tcb
->SndWl2
= Tcb
->Iss
+ 1;
122 if (TCP_FLG_ON (Opt
->Flag
, TCP_OPTION_RCVD_MSS
)) {
123 Tcb
->SndMss
= (UINT16
) MAX (64, Opt
->Mss
);
125 RcvMss
= TcpGetRcvMss (Tcb
->Sk
);
126 if (Tcb
->SndMss
> RcvMss
) {
127 Tcb
->SndMss
= RcvMss
;
132 // One end doesn't support MSS option, use default.
137 Tcb
->CWnd
= Tcb
->SndMss
;
140 Tcb
->RcvNxt
= Tcb
->Irs
+ 1;
142 Tcb
->RcvWl2
= Tcb
->RcvNxt
;
144 if (TCP_FLG_ON (Opt
->Flag
, TCP_OPTION_RCVD_WS
) && !TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_NO_WS
)) {
146 Tcb
->SndWndScale
= Opt
->WndScale
;
148 Tcb
->RcvWndScale
= TcpComputeScale (Tcb
);
149 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_WS
);
153 // One end doesn't support window scale option. use zero.
155 Tcb
->RcvWndScale
= 0;
158 if (TCP_FLG_ON (Opt
->Flag
, TCP_OPTION_RCVD_TS
) && !TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_NO_TS
)) {
160 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_TS
);
161 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_RCVD_TS
);
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
;
173 Check whether one IP address equals the other.
175 @param[in] Ip1 Pointer to IP address to be checked.
176 @param[in] Ip2 Pointer to IP address to be checked.
177 @param[in] Version IP_VERSION_4 indicates the IP address is an IPv4 address,
178 IP_VERSION_6 indicates the IP address is an IPv6 address.
180 @retval TRUE Ip1 equals Ip2.
181 @retval FALSE Ip1 does not equal Ip2.
186 IN EFI_IP_ADDRESS
*Ip1
,
187 IN EFI_IP_ADDRESS
*Ip2
,
191 ASSERT ((Version
== IP_VERSION_4
) || (Version
== IP_VERSION_6
));
193 if (Version
== IP_VERSION_4
) {
194 return (BOOLEAN
) (Ip1
->Addr
[0] == Ip2
->Addr
[0]);
196 return (BOOLEAN
) EFI_IP6_EQUAL (&Ip1
->v6
, &Ip2
->v6
);
201 Check whether one IP address is filled with ZERO.
203 @param[in] Ip Pointer to the IP address to be checked.
204 @param[in] Version IP_VERSION_4 indicates the IP address is an IPv4 address,
205 IP_VERSION_6 indicates the IP address is an IPv6 address.
207 @retval TRUE Ip is all zero address.
208 @retval FALSE Ip is not all zero address.
213 IN EFI_IP_ADDRESS
*Ip
,
217 ASSERT ((Version
== IP_VERSION_4
) || (Version
== IP_VERSION_6
));
219 if (Version
== IP_VERSION_4
) {
220 return (BOOLEAN
) (Ip
->Addr
[0] == 0);
222 return (BOOLEAN
) ((Ip
->Addr
[0] == 0) && (Ip
->Addr
[1] == 0) &&
223 (Ip
->Addr
[2] == 0) && (Ip
->Addr
[3] == 0));
228 Locate a listen TCB that matchs the Local and Remote.
230 @param[in] Local Pointer to the local (IP, Port).
231 @param[in] Remote Pointer to the remote (IP, Port).
232 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,
233 IP_VERSION_6 indicates TCP is running on IP6 stack.
235 @return Pointer to the TCP_CB with the least number of wildcards,
236 if NULL no match is found.
255 NET_LIST_FOR_EACH (Entry
, &mTcpListenQue
) {
256 Node
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
258 if ((Version
!= Node
->Sk
->IpVersion
) ||
259 (Local
->Port
!= Node
->LocalEnd
.Port
) ||
260 !TCP_PEER_MATCH (Remote
, &Node
->RemoteEnd
, Version
) ||
261 !TCP_PEER_MATCH (Local
, &Node
->LocalEnd
, Version
)
268 // Compute the number of wildcard
271 if (TcpIsIpZero (&Node
->RemoteEnd
.Ip
, Version
)) {
275 if (Node
->RemoteEnd
.Port
== 0) {
279 if (TcpIsIpZero (&Node
->LocalEnd
.Ip
, Version
)) {
297 Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.
299 @param[in] Addr Pointer to the IP address needs to match.
300 @param[in] Port The port number needs to match.
301 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,
302 IP_VERSION_6 indicates TCP is running on IP6 stack.
305 @retval TRUE The Tcb which matches the <Addr Port> pair exists.
306 @retval FALSE Otherwise
311 IN EFI_IP_ADDRESS
*Addr
,
316 TCP_PORTNO LocalPort
;
320 ASSERT ((Addr
!= NULL
) && (Port
!= 0));
322 LocalPort
= HTONS (Port
);
324 NET_LIST_FOR_EACH (Entry
, &mTcpListenQue
) {
325 Tcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
327 if ((Version
== Tcb
->Sk
->IpVersion
) &&
328 TcpIsIpEqual (Addr
, &Tcb
->LocalEnd
.Ip
, Version
) &&
329 (LocalPort
== Tcb
->LocalEnd
.Port
)
336 NET_LIST_FOR_EACH (Entry
, &mTcpRunQue
) {
337 Tcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
339 if ((Version
== Tcb
->Sk
->IpVersion
) &&
340 TcpIsIpEqual (Addr
, &Tcb
->LocalEnd
.Ip
, Version
) &&
341 (LocalPort
== Tcb
->LocalEnd
.Port
)
352 Locate the TCP_CB related to the socket pair.
354 @param[in] LocalPort The local port number.
355 @param[in] LocalIp The local IP address.
356 @param[in] RemotePort The remote port number.
357 @param[in] RemoteIp The remote IP address.
358 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,
359 IP_VERSION_6 indicates TCP is running on IP6 stack.
360 @param[in] Syn If TRUE, the listen sockets are searched.
362 @return Pointer to the related TCP_CB. If NULL, no match is found.
367 IN TCP_PORTNO LocalPort
,
368 IN EFI_IP_ADDRESS
*LocalIp
,
369 IN TCP_PORTNO RemotePort
,
370 IN EFI_IP_ADDRESS
*RemoteIp
,
380 Local
.Port
= LocalPort
;
381 Remote
.Port
= RemotePort
;
383 CopyMem (&Local
.Ip
, LocalIp
, sizeof (EFI_IP_ADDRESS
));
384 CopyMem (&Remote
.Ip
, RemoteIp
, sizeof (EFI_IP_ADDRESS
));
387 // First check for exact match.
389 NET_LIST_FOR_EACH (Entry
, &mTcpRunQue
) {
390 Tcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
392 if ((Version
== Tcb
->Sk
->IpVersion
) &&
393 TCP_PEER_EQUAL (&Remote
, &Tcb
->RemoteEnd
, Version
) &&
394 TCP_PEER_EQUAL (&Local
, &Tcb
->LocalEnd
, Version
)
397 RemoveEntryList (&Tcb
->List
);
398 InsertHeadList (&mTcpRunQue
, &Tcb
->List
);
405 // Only check the listen queue when the SYN flag is on.
408 return TcpLocateListenTcb (&Local
, &Remote
, Version
);
415 Insert a Tcb into the proper queue.
417 @param[in] Tcb Pointer to the TCP_CB to be inserted.
419 @retval 0 The Tcb was inserted successfully.
420 @retval -1 Error condition occurred.
431 TCP_PROTO_DATA
*TcpProto
;
436 (Tcb
->State
== TCP_LISTEN
) ||
437 (Tcb
->State
== TCP_SYN_SENT
) ||
438 (Tcb
->State
== TCP_SYN_RCVD
) ||
439 (Tcb
->State
== TCP_CLOSED
)
443 if (Tcb
->LocalEnd
.Port
== 0) {
449 if (Tcb
->State
== TCP_LISTEN
) {
450 Head
= &mTcpListenQue
;
454 // Check that the Tcb isn't already on the list.
456 NET_LIST_FOR_EACH (Entry
, Head
) {
457 Node
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
459 if (TCP_PEER_EQUAL (&Tcb
->LocalEnd
, &Node
->LocalEnd
, Tcb
->Sk
->IpVersion
) &&
460 TCP_PEER_EQUAL (&Tcb
->RemoteEnd
, &Node
->RemoteEnd
, Tcb
->Sk
->IpVersion
)
467 InsertHeadList (Head
, &Tcb
->List
);
469 TcpProto
= (TCP_PROTO_DATA
*) Tcb
->Sk
->ProtoReserved
;
470 TcpSetVariableData (TcpProto
->TcpService
);
476 Clone a TCP_CB from Tcb.
478 @param[in] Tcb Pointer to the TCP_CB to be cloned.
480 @return Pointer to the new cloned TCP_CB; if NULL, error condition occurred.
490 Clone
= AllocateZeroPool (sizeof (TCP_CB
));
496 CopyMem (Clone
, Tcb
, sizeof (TCP_CB
));
499 // Increase the reference count of the shared IpInfo.
501 NET_GET_REF (Tcb
->IpInfo
);
503 InitializeListHead (&Clone
->List
);
504 InitializeListHead (&Clone
->SndQue
);
505 InitializeListHead (&Clone
->RcvQue
);
507 Clone
->Sk
= SockClone (Tcb
->Sk
);
508 if (Clone
->Sk
== NULL
) {
509 DEBUG ((EFI_D_ERROR
, "TcpCloneTcb: failed to clone a sock\n"));
514 ((TCP_PROTO_DATA
*) (Clone
->Sk
->ProtoReserved
))->TcpPcb
= Clone
;
520 Compute an ISS to be used by a new connection.
522 @return The resulting ISS.
530 mTcpGlobalIss
+= TCP_ISS_INCREMENT_1
;
531 return mTcpGlobalIss
;
537 @param[in] Sock Pointer to the socket to get mss.
539 @return The mss size.
547 EFI_IP4_MODE_DATA Ip4Mode
;
548 EFI_IP6_MODE_DATA Ip6Mode
;
549 EFI_IP4_PROTOCOL
*Ip4
;
550 EFI_IP6_PROTOCOL
*Ip6
;
551 TCP_PROTO_DATA
*TcpProto
;
553 ASSERT (Sock
!= NULL
);
555 ZeroMem (&Ip4Mode
, sizeof (EFI_IP4_MODE_DATA
));
556 ZeroMem (&Ip6Mode
, sizeof (EFI_IP6_MODE_DATA
));
558 TcpProto
= (TCP_PROTO_DATA
*) Sock
->ProtoReserved
;
560 if (Sock
->IpVersion
== IP_VERSION_4
) {
561 Ip4
= TcpProto
->TcpService
->IpIo
->Ip
.Ip4
;
562 ASSERT (Ip4
!= NULL
);
563 Ip4
->GetModeData (Ip4
, &Ip4Mode
, NULL
, NULL
);
565 return (UINT16
) (Ip4Mode
.MaxPacketSize
- sizeof (TCP_HEAD
));
567 Ip6
= TcpProto
->TcpService
->IpIo
->Ip
.Ip6
;
568 ASSERT (Ip6
!= NULL
);
569 Ip6
->GetModeData (Ip6
, &Ip6Mode
, NULL
, NULL
);
571 return (UINT16
) (Ip6Mode
.MaxPacketSize
- sizeof (TCP_HEAD
));
578 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
579 @param[in] State The state to be set.
588 ASSERT (Tcb
->State
< (sizeof (mTcpStateName
) / sizeof (CHAR16
*)));
589 ASSERT (State
< (sizeof (mTcpStateName
) / sizeof (CHAR16
*)));
593 "Tcb (%p) state %s --> %s\n",
595 mTcpStateName
[Tcb
->State
],
596 mTcpStateName
[State
])
602 case TCP_ESTABLISHED
:
604 SockConnEstablished (Tcb
->Sk
);
606 if (Tcb
->Parent
!= NULL
) {
608 // A new connection is accepted by a listening socket. Install
611 TcpInstallDevicePath (Tcb
->Sk
);
618 SockConnClosed (Tcb
->Sk
);
627 Compute the TCP segment's checksum.
629 @param[in] Nbuf Pointer to the buffer that contains the TCP segment.
630 @param[in] HeadSum The checksum value of the fixed part of pseudo header.
632 @return The checksum value.
643 Checksum
= NetbufChecksum (Nbuf
);
644 Checksum
= NetAddChecksum (Checksum
, HeadSum
);
646 Checksum
= NetAddChecksum (
648 HTONS ((UINT16
) Nbuf
->TotalSize
)
651 return (UINT16
) (~Checksum
);
655 Translate the information from the head of the received TCP
656 segment Nbuf contents and fill it into a TCP_SEG structure.
658 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
659 @param[in, out] Nbuf Pointer to the buffer contains the TCP segment.
661 @return Pointer to the TCP_SEG that contains the translated TCP head information.
673 Seg
= TCPSEG_NETBUF (Nbuf
);
674 Head
= (TCP_HEAD
*) NetbufGetByte (Nbuf
, 0, NULL
);
675 ASSERT (Head
!= NULL
);
679 Seg
->Seq
= NTOHL (Head
->Seq
);
680 Seg
->Ack
= NTOHL (Head
->Ack
);
681 Seg
->End
= Seg
->Seq
+ (Nbuf
->TotalSize
- (Head
->HeadLen
<< 2));
683 Seg
->Urg
= NTOHS (Head
->Urg
);
684 Seg
->Wnd
= (NTOHS (Head
->Wnd
) << Tcb
->SndWndScale
);
685 Seg
->Flag
= Head
->Flag
;
688 // SYN and FIN flag occupy one sequence space each.
690 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_SYN
)) {
692 // RFC requires that the initial window not be scaled.
694 Seg
->Wnd
= NTOHS (Head
->Wnd
);
698 if (TCP_FLG_ON (Seg
->Flag
, TCP_FLG_FIN
)) {
706 Initialize an active connection.
708 @param[in, out] Tcb Pointer to the TCP_CB that wants to initiate a
717 TcpInitTcbLocal (Tcb
);
718 TcpSetState (Tcb
, TCP_SYN_SENT
);
720 TcpSetTimer (Tcb
, TCP_TIMER_CONNECT
, Tcb
->ConnectTimeout
);
721 TcpToSendData (Tcb
, 1);
725 Initiate the connection close procedure, called when
726 applications want to close the connection.
728 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
736 ASSERT (Tcb
!= NULL
);
738 if (!IsListEmpty (&Tcb
->RcvQue
) || GET_RCV_DATASIZE (Tcb
->Sk
) != 0) {
742 "TcpOnAppClose: connection reset because data is lost for TCB %p\n",
746 TcpResetConnection (Tcb
);
751 switch (Tcb
->State
) {
755 TcpSetState (Tcb
, TCP_CLOSED
);
759 case TCP_ESTABLISHED
:
760 TcpSetState (Tcb
, TCP_FIN_WAIT_1
);
764 TcpSetState (Tcb
, TCP_LAST_ACK
);
770 TcpToSendData (Tcb
, 1);
774 Check whether the application's newly delivered data can be sent out.
776 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
778 @retval 0 The data has been sent out successfully.
779 @retval -1 The Tcb is not in a state that data is permitted to
789 switch (Tcb
->State
) {
800 case TCP_ESTABLISHED
:
802 TcpToSendData (Tcb
, 0);
820 Application has consumed some data. Check whether
821 to send a window update ack or a delayed ack.
823 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
833 switch (Tcb
->State
) {
834 case TCP_ESTABLISHED
:
835 TcpOld
= TcpRcvWinOld (Tcb
);
836 if (TcpRcvWinNow (Tcb
) > TcpOld
) {
838 if (TcpOld
< Tcb
->RcvMss
) {
842 "TcpOnAppConsume: send a window update for a window closed Tcb %p\n",
847 } else if (Tcb
->DelayedAck
== 0) {
851 "TcpOnAppConsume: scheduled a delayed ACK to update window for Tcb %p\n",
867 Abort the connection by sending a reset segment. Called
868 when the application wants to abort the connection.
870 @param[in] Tcb Pointer to the TCP_CB of the TCP instance.
880 "TcpOnAppAbort: connection reset issued by application for TCB %p\n",
884 switch (Tcb
->State
) {
886 case TCP_ESTABLISHED
:
890 TcpResetConnection (Tcb
);
896 TcpSetState (Tcb
, TCP_CLOSED
);
900 Reset the connection related with Tcb.
902 @param[in] Tcb Pointer to the TCP_CB of the connection to be reset.
913 Nbuf
= NetbufAlloc (TCP_MAX_HEAD
);
919 Nhead
= (TCP_HEAD
*) NetbufAllocSpace (
925 ASSERT (Nhead
!= NULL
);
929 Nhead
->Flag
= TCP_FLG_RST
;
930 Nhead
->Seq
= HTONL (Tcb
->SndNxt
);
931 Nhead
->Ack
= HTONL (Tcb
->RcvNxt
);
932 Nhead
->SrcPort
= Tcb
->LocalEnd
.Port
;
933 Nhead
->DstPort
= Tcb
->RemoteEnd
.Port
;
934 Nhead
->HeadLen
= (UINT8
) (sizeof (TCP_HEAD
) >> 2);
936 Nhead
->Wnd
= HTONS (0xFFFF);
939 Nhead
->Checksum
= TcpChecksum (Nbuf
, Tcb
->HeadSum
);
941 TcpSendIpPacket (Tcb
, Nbuf
, &Tcb
->LocalEnd
.Ip
, &Tcb
->RemoteEnd
.Ip
, Tcb
->Sk
->IpVersion
);
947 Set the Tcp variable data.
949 @param[in] TcpService Tcp service data.
951 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.
952 @retval other Set variable failed.
957 IN TCP_SERVICE_DATA
*TcpService
960 EFI_GUID
*ServiceBindingGuid
;
961 UINT32 NumConfiguredInstance
;
964 TCP_PROTO_DATA
*TcpProto
;
965 UINTN VariableDataSize
;
966 EFI_TCP4_VARIABLE_DATA
*Tcp4VariableData
;
967 EFI_TCP4_SERVICE_POINT
*Tcp4ServicePoint
;
968 EFI_TCP6_VARIABLE_DATA
*Tcp6VariableData
;
969 EFI_TCP6_SERVICE_POINT
*Tcp6ServicePoint
;
971 CHAR16
*NewMacString
;
974 if (TcpService
->IpVersion
== IP_VERSION_4
) {
975 ServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
977 ServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
980 NumConfiguredInstance
= 0;
981 Tcp4VariableData
= NULL
;
982 Tcp6VariableData
= NULL
;
985 // Go through the running queue to count the instances.
987 NET_LIST_FOR_EACH (Entry
, &mTcpRunQue
) {
988 TcpPcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
990 TcpProto
= (TCP_PROTO_DATA
*) TcpPcb
->Sk
->ProtoReserved
;
992 if (TcpProto
->TcpService
== TcpService
) {
994 // This tcp instance belongs to the TcpService.
996 NumConfiguredInstance
++;
1001 // Go through the listening queue to count the instances.
1003 NET_LIST_FOR_EACH (Entry
, &mTcpListenQue
) {
1004 TcpPcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
1006 TcpProto
= (TCP_PROTO_DATA
*) TcpPcb
->Sk
->ProtoReserved
;
1008 if (TcpProto
->TcpService
== TcpService
) {
1010 // This tcp instance belongs to the TcpService.
1012 NumConfiguredInstance
++;
1016 Tcp4ServicePoint
= NULL
;
1017 Tcp6ServicePoint
= NULL
;
1020 // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,
1021 // we should add extra buffers for the service points only if the number of configured
1022 // children is more than one.
1024 if (TcpService
->IpVersion
== IP_VERSION_4
) {
1025 VariableDataSize
= sizeof (EFI_TCP4_VARIABLE_DATA
);
1027 if (NumConfiguredInstance
> 1) {
1028 VariableDataSize
+= sizeof (EFI_TCP4_SERVICE_POINT
) * (NumConfiguredInstance
- 1);
1031 Tcp4VariableData
= AllocateZeroPool (VariableDataSize
);
1032 if (Tcp4VariableData
== NULL
) {
1033 return EFI_OUT_OF_RESOURCES
;
1036 Tcp4VariableData
->DriverHandle
= TcpService
->DriverBindingHandle
;
1037 Tcp4VariableData
->ServiceCount
= NumConfiguredInstance
;
1039 Tcp4ServicePoint
= &Tcp4VariableData
->Services
[0];
1040 VariableData
= Tcp4VariableData
;
1042 VariableDataSize
= sizeof (EFI_TCP6_VARIABLE_DATA
);
1044 if (NumConfiguredInstance
> 1) {
1045 VariableDataSize
+= sizeof (EFI_TCP6_SERVICE_POINT
) * (NumConfiguredInstance
- 1);
1048 Tcp6VariableData
= AllocateZeroPool (VariableDataSize
);
1049 if (Tcp6VariableData
== NULL
) {
1050 return EFI_OUT_OF_RESOURCES
;
1053 Tcp6VariableData
->DriverHandle
= TcpService
->DriverBindingHandle
;
1054 Tcp6VariableData
->ServiceCount
= NumConfiguredInstance
;
1056 Tcp6ServicePoint
= &Tcp6VariableData
->Services
[0];
1057 VariableData
= Tcp6VariableData
;
1061 // Go through the running queue to fill the service points.
1063 NET_LIST_FOR_EACH (Entry
, &mTcpRunQue
) {
1064 TcpPcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
1066 TcpProto
= (TCP_PROTO_DATA
*) TcpPcb
->Sk
->ProtoReserved
;
1068 if (TcpProto
->TcpService
== TcpService
) {
1070 // This tcp instance belongs to the TcpService.
1072 if (TcpService
->IpVersion
== IP_VERSION_4
) {
1073 Tcp4ServicePoint
->InstanceHandle
= TcpPcb
->Sk
->SockHandle
;
1074 CopyMem (&Tcp4ServicePoint
->LocalAddress
, &TcpPcb
->LocalEnd
.Ip
, sizeof (EFI_IPv4_ADDRESS
));
1075 Tcp4ServicePoint
->LocalPort
= NTOHS (TcpPcb
->LocalEnd
.Port
);
1076 CopyMem (&Tcp4ServicePoint
->RemoteAddress
, &TcpPcb
->RemoteEnd
.Ip
, sizeof (EFI_IPv4_ADDRESS
));
1077 Tcp4ServicePoint
->RemotePort
= NTOHS (TcpPcb
->RemoteEnd
.Port
);
1081 Tcp6ServicePoint
->InstanceHandle
= TcpPcb
->Sk
->SockHandle
;
1082 IP6_COPY_ADDRESS (&Tcp6ServicePoint
->LocalAddress
, &TcpPcb
->LocalEnd
.Ip
);
1083 Tcp6ServicePoint
->LocalPort
= NTOHS (TcpPcb
->LocalEnd
.Port
);
1084 IP6_COPY_ADDRESS (&Tcp6ServicePoint
->RemoteAddress
, &TcpPcb
->RemoteEnd
.Ip
);
1085 Tcp6ServicePoint
->RemotePort
= NTOHS (TcpPcb
->RemoteEnd
.Port
);
1093 // Go through the listening queue to fill the service points.
1095 NET_LIST_FOR_EACH (Entry
, &mTcpListenQue
) {
1096 TcpPcb
= NET_LIST_USER_STRUCT (Entry
, TCP_CB
, List
);
1098 TcpProto
= (TCP_PROTO_DATA
*) TcpPcb
->Sk
->ProtoReserved
;
1100 if (TcpProto
->TcpService
== TcpService
) {
1102 // This tcp instance belongs to the TcpService.
1104 if (TcpService
->IpVersion
== IP_VERSION_4
) {
1105 Tcp4ServicePoint
->InstanceHandle
= TcpPcb
->Sk
->SockHandle
;
1106 CopyMem (&Tcp4ServicePoint
->LocalAddress
, &TcpPcb
->LocalEnd
.Ip
, sizeof (EFI_IPv4_ADDRESS
));
1107 Tcp4ServicePoint
->LocalPort
= NTOHS (TcpPcb
->LocalEnd
.Port
);
1108 CopyMem (&Tcp4ServicePoint
->RemoteAddress
, &TcpPcb
->RemoteEnd
.Ip
, sizeof (EFI_IPv4_ADDRESS
));
1109 Tcp4ServicePoint
->RemotePort
= NTOHS (TcpPcb
->RemoteEnd
.Port
);
1113 Tcp6ServicePoint
->InstanceHandle
= TcpPcb
->Sk
->SockHandle
;
1114 IP6_COPY_ADDRESS (&Tcp6ServicePoint
->LocalAddress
, &TcpPcb
->LocalEnd
.Ip
);
1115 Tcp6ServicePoint
->LocalPort
= NTOHS (TcpPcb
->LocalEnd
.Port
);
1116 IP6_COPY_ADDRESS (&Tcp6ServicePoint
->RemoteAddress
, &TcpPcb
->RemoteEnd
.Ip
);
1117 Tcp6ServicePoint
->RemotePort
= NTOHS (TcpPcb
->RemoteEnd
.Port
);
1125 // Get the mac string.
1127 Status
= NetLibGetMacString (
1128 TcpService
->ControllerHandle
,
1129 TcpService
->DriverBindingHandle
,
1132 if (EFI_ERROR (Status
)) {
1136 if (TcpService
->MacString
!= NULL
) {
1138 // The variable is set already. We're going to update it.
1140 if (StrCmp (TcpService
->MacString
, NewMacString
) != 0) {
1142 // The mac address is changed. Delete the previous variable first.
1145 TcpService
->MacString
,
1147 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1153 FreePool (TcpService
->MacString
);
1156 TcpService
->MacString
= NewMacString
;
1158 Status
= gRT
->SetVariable (
1159 TcpService
->MacString
,
1161 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1168 FreePool (VariableData
);
1174 Clear the variable and free the resource.
1176 @param[in] TcpService Tcp service data.
1180 TcpClearVariableData (
1181 IN TCP_SERVICE_DATA
*TcpService
1184 EFI_GUID
*ServiceBindingGuid
;
1186 ASSERT (TcpService
->MacString
!= NULL
);
1188 if (TcpService
->IpVersion
== IP_VERSION_4
) {
1189 ServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
1191 ServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
1195 TcpService
->MacString
,
1197 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1202 FreePool (TcpService
->MacString
);
1203 TcpService
->MacString
= NULL
;
1207 Install the device path protocol on the TCP instance.
1209 @param[in] Sock Pointer to the socket representing the TCP instance.
1211 @retval EFI_SUCCESS The device path protocol was installed.
1212 @retval other Failed to install the device path protocol.
1216 TcpInstallDevicePath (
1220 TCP_PROTO_DATA
*TcpProto
;
1221 TCP_SERVICE_DATA
*TcpService
;
1223 IPv4_DEVICE_PATH Ip4DPathNode
;
1224 IPv6_DEVICE_PATH Ip6DPathNode
;
1225 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1227 TCP_PORTNO LocalPort
;
1228 TCP_PORTNO RemotePort
;
1230 TcpProto
= (TCP_PROTO_DATA
*) Sock
->ProtoReserved
;
1231 TcpService
= TcpProto
->TcpService
;
1232 Tcb
= TcpProto
->TcpPcb
;
1234 LocalPort
= NTOHS (Tcb
->LocalEnd
.Port
);
1235 RemotePort
= NTOHS (Tcb
->RemoteEnd
.Port
);
1236 if (Sock
->IpVersion
== IP_VERSION_4
) {
1237 NetLibCreateIPv4DPathNode (
1239 TcpService
->ControllerHandle
,
1240 Tcb
->LocalEnd
.Ip
.Addr
[0],
1242 Tcb
->RemoteEnd
.Ip
.Addr
[0],
1248 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &Ip4DPathNode
;
1250 NetLibCreateIPv6DPathNode (
1252 TcpService
->ControllerHandle
,
1253 &Tcb
->LocalEnd
.Ip
.v6
,
1255 &Tcb
->RemoteEnd
.Ip
.v6
,
1260 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &Ip6DPathNode
;
1263 Sock
->DevicePath
= AppendDevicePathNode (Sock
->ParentDevicePath
, DevicePath
);
1264 if (Sock
->DevicePath
== NULL
) {
1265 return EFI_OUT_OF_RESOURCES
;
1268 Status
= gBS
->InstallProtocolInterface (
1270 &gEfiDevicePathProtocolGuid
,
1271 EFI_NATIVE_INTERFACE
,
1274 if (EFI_ERROR (Status
)) {
1275 FreePool (Sock
->DevicePath
);
1276 Sock
->DevicePath
= NULL
;