2 This library is used to share code between UEFI network stack modules.
3 It provides the helper routines to access TCP service.
5 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Library/TcpIoLib.h>
13 #include <Library/BaseLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/UefiBootServicesTableLib.h>
16 #include <Library/MemoryAllocationLib.h>
17 #include <Library/BaseMemoryLib.h>
20 The common notify function associated with various TcpIo events.
22 @param[in] Event The event signaled.
23 @param[in] Context The context.
33 if ((Event
== NULL
) || (Context
== NULL
)) {
37 *((BOOLEAN
*)Context
) = TRUE
;
41 The internal function for delay configuring TCP6 when IP6 driver is still in DAD.
43 @param[in] Tcp6 The EFI_TCP6_PROTOCOL protocol instance.
44 @param[in] Tcp6ConfigData The Tcp6 configuration data.
46 @retval EFI_SUCCESS The operational settings successfully
48 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
49 @retval Others Failed to finish the operation.
54 IN EFI_TCP6_PROTOCOL
*Tcp6
,
55 IN EFI_TCP6_CONFIG_DATA
*Tcp6ConfigData
61 if ((Tcp6
== NULL
) || (Tcp6ConfigData
== NULL
)) {
62 return EFI_INVALID_PARAMETER
;
66 Status
= gBS
->CreateEvent (
73 if (EFI_ERROR (Status
)) {
77 Status
= gBS
->SetTimer (
80 TCP_GET_MAPPING_TIMEOUT
83 if (EFI_ERROR (Status
)) {
87 while (EFI_ERROR (gBS
->CheckEvent (Event
))) {
90 Status
= Tcp6
->Configure (Tcp6
, Tcp6ConfigData
);
92 if (!EFI_ERROR (Status
)) {
100 gBS
->CloseEvent (Event
);
107 Create a TCP socket with the specified configuration data.
109 @param[in] Image The handle of the driver image.
110 @param[in] Controller The handle of the controller.
111 @param[in] TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6.
112 @param[in] ConfigData The Tcp configuration data.
113 @param[out] TcpIo The TcpIo.
115 @retval EFI_SUCCESS The TCP socket is created and configured.
116 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
117 @retval EFI_UNSUPPORTED One or more of the control options are not
118 supported in the implementation.
119 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
120 @retval Others Failed to create the TCP socket or configure it.
127 IN EFI_HANDLE Controller
,
129 IN TCP_IO_CONFIG_DATA
*ConfigData
,
135 EFI_GUID
*ServiceBindingGuid
;
136 EFI_GUID
*ProtocolGuid
;
138 EFI_TCP4_OPTION ControlOption
;
139 EFI_TCP4_CONFIG_DATA Tcp4ConfigData
;
140 EFI_TCP4_ACCESS_POINT
*AccessPoint4
;
141 EFI_TCP4_PROTOCOL
*Tcp4
;
142 EFI_TCP6_CONFIG_DATA Tcp6ConfigData
;
143 EFI_TCP6_ACCESS_POINT
*AccessPoint6
;
144 EFI_TCP6_PROTOCOL
*Tcp6
;
145 EFI_TCP4_RECEIVE_DATA
*RxData
;
147 if ((Image
== NULL
) || (Controller
== NULL
) || (ConfigData
== NULL
) || (TcpIo
== NULL
)) {
148 return EFI_INVALID_PARAMETER
;
154 ZeroMem (TcpIo
, sizeof (TCP_IO
));
156 if (TcpVersion
== TCP_VERSION_4
) {
157 ServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
158 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
159 Interface
= (VOID
**)(&TcpIo
->Tcp
.Tcp4
);
160 } else if (TcpVersion
== TCP_VERSION_6
) {
161 ServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
162 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
163 Interface
= (VOID
**)(&TcpIo
->Tcp
.Tcp6
);
165 return EFI_UNSUPPORTED
;
168 TcpIo
->TcpVersion
= TcpVersion
;
171 // Create the TCP child instance and get the TCP protocol.
173 Status
= NetLibCreateServiceChild (
179 if (EFI_ERROR (Status
)) {
183 Status
= gBS
->OpenProtocol (
189 EFI_OPEN_PROTOCOL_BY_DRIVER
191 if (EFI_ERROR (Status
) || (*Interface
== NULL
)) {
195 if (TcpVersion
== TCP_VERSION_4
) {
196 Tcp4
= TcpIo
->Tcp
.Tcp4
;
198 Tcp6
= TcpIo
->Tcp
.Tcp6
;
201 TcpIo
->Image
= Image
;
202 TcpIo
->Controller
= Controller
;
205 // Set the configuration parameters.
207 ControlOption
.ReceiveBufferSize
= 0x200000;
208 ControlOption
.SendBufferSize
= 0x200000;
209 ControlOption
.MaxSynBackLog
= 0;
210 ControlOption
.ConnectionTimeout
= 0;
211 ControlOption
.DataRetries
= 6;
212 ControlOption
.FinTimeout
= 0;
213 ControlOption
.TimeWaitTimeout
= 0;
214 ControlOption
.KeepAliveProbes
= 4;
215 ControlOption
.KeepAliveTime
= 0;
216 ControlOption
.KeepAliveInterval
= 0;
217 ControlOption
.EnableNagle
= FALSE
;
218 ControlOption
.EnableTimeStamp
= FALSE
;
219 ControlOption
.EnableWindowScaling
= TRUE
;
220 ControlOption
.EnableSelectiveAck
= FALSE
;
221 ControlOption
.EnablePathMtuDiscovery
= FALSE
;
223 if (TcpVersion
== TCP_VERSION_4
) {
224 Tcp4ConfigData
.TypeOfService
= 8;
225 Tcp4ConfigData
.TimeToLive
= 255;
226 Tcp4ConfigData
.ControlOption
= &ControlOption
;
228 AccessPoint4
= &Tcp4ConfigData
.AccessPoint
;
230 ZeroMem (AccessPoint4
, sizeof (EFI_TCP4_ACCESS_POINT
));
231 AccessPoint4
->StationPort
= ConfigData
->Tcp4IoConfigData
.StationPort
;
232 AccessPoint4
->RemotePort
= ConfigData
->Tcp4IoConfigData
.RemotePort
;
233 AccessPoint4
->ActiveFlag
= ConfigData
->Tcp4IoConfigData
.ActiveFlag
;
236 &AccessPoint4
->StationAddress
,
237 &ConfigData
->Tcp4IoConfigData
.LocalIp
,
238 sizeof (EFI_IPv4_ADDRESS
)
241 &AccessPoint4
->SubnetMask
,
242 &ConfigData
->Tcp4IoConfigData
.SubnetMask
,
243 sizeof (EFI_IPv4_ADDRESS
)
246 &AccessPoint4
->RemoteAddress
,
247 &ConfigData
->Tcp4IoConfigData
.RemoteIp
,
248 sizeof (EFI_IPv4_ADDRESS
)
251 ASSERT (Tcp4
!= NULL
);
254 // Configure the TCP4 protocol.
256 Status
= Tcp4
->Configure (Tcp4
, &Tcp4ConfigData
);
257 if (EFI_ERROR (Status
)) {
261 if (!EFI_IP4_EQUAL (&ConfigData
->Tcp4IoConfigData
.Gateway
, &mZeroIp4Addr
)) {
263 // The gateway is not zero. Add the default route manually.
265 Status
= Tcp4
->Routes (
270 &ConfigData
->Tcp4IoConfigData
.Gateway
272 if (EFI_ERROR (Status
)) {
277 Tcp6ConfigData
.TrafficClass
= 0;
278 Tcp6ConfigData
.HopLimit
= 255;
279 Tcp6ConfigData
.ControlOption
= (EFI_TCP6_OPTION
*)&ControlOption
;
281 AccessPoint6
= &Tcp6ConfigData
.AccessPoint
;
283 ZeroMem (AccessPoint6
, sizeof (EFI_TCP6_ACCESS_POINT
));
284 AccessPoint6
->StationPort
= ConfigData
->Tcp6IoConfigData
.StationPort
;
285 AccessPoint6
->RemotePort
= ConfigData
->Tcp6IoConfigData
.RemotePort
;
286 AccessPoint6
->ActiveFlag
= ConfigData
->Tcp6IoConfigData
.ActiveFlag
;
288 IP6_COPY_ADDRESS (&AccessPoint6
->RemoteAddress
, &ConfigData
->Tcp6IoConfigData
.RemoteIp
);
290 ASSERT (Tcp6
!= NULL
);
292 // Configure the TCP6 protocol.
294 Status
= Tcp6
->Configure (Tcp6
, &Tcp6ConfigData
);
295 if (Status
== EFI_NO_MAPPING
) {
296 Status
= TcpIoGetMapping (Tcp6
, &Tcp6ConfigData
);
299 if (EFI_ERROR (Status
)) {
305 // Create events for various asynchronous operations.
307 Status
= gBS
->CreateEvent (
314 if (EFI_ERROR (Status
)) {
318 TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
320 Status
= gBS
->CreateEvent (
324 &TcpIo
->IsListenDone
,
327 if (EFI_ERROR (Status
)) {
331 TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
333 Status
= gBS
->CreateEvent (
340 if (EFI_ERROR (Status
)) {
344 TcpIo
->TxToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
346 Status
= gBS
->CreateEvent (
353 if (EFI_ERROR (Status
)) {
357 TcpIo
->RxToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
359 RxData
= (EFI_TCP4_RECEIVE_DATA
*)AllocateZeroPool (sizeof (EFI_TCP4_RECEIVE_DATA
));
360 if (RxData
== NULL
) {
361 Status
= EFI_OUT_OF_RESOURCES
;
365 TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
= RxData
;
367 Status
= gBS
->CreateEvent (
374 if (EFI_ERROR (Status
)) {
378 TcpIo
->CloseToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
384 TcpIoDestroySocket (TcpIo
);
392 @param[in] TcpIo The TcpIo which wraps the socket to be destroyed.
402 EFI_TCP4_PROTOCOL
*Tcp4
;
403 EFI_TCP6_PROTOCOL
*Tcp6
;
405 EFI_GUID
*ServiceBindingGuid
;
406 EFI_GUID
*ProtocolGuid
;
407 EFI_HANDLE ChildHandle
;
413 TcpVersion
= TcpIo
->TcpVersion
;
415 if ((TcpVersion
!= TCP_VERSION_4
) && (TcpVersion
!= TCP_VERSION_6
)) {
419 Event
= TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
.Event
;
422 gBS
->CloseEvent (Event
);
425 Event
= TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
.Event
;
428 gBS
->CloseEvent (Event
);
431 Event
= TcpIo
->TxToken
.Tcp4Token
.CompletionToken
.Event
;
434 gBS
->CloseEvent (Event
);
437 Event
= TcpIo
->RxToken
.Tcp4Token
.CompletionToken
.Event
;
440 gBS
->CloseEvent (Event
);
443 Event
= TcpIo
->CloseToken
.Tcp4Token
.CompletionToken
.Event
;
446 gBS
->CloseEvent (Event
);
449 if (TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
!= NULL
) {
450 FreePool (TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
);
456 if (TcpVersion
== TCP_VERSION_4
) {
457 ServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
458 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
459 Tcp4
= TcpIo
->Tcp
.Tcp4
;
461 Tcp4
->Configure (Tcp4
, NULL
);
464 ServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
465 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
466 Tcp6
= TcpIo
->Tcp
.Tcp6
;
468 Tcp6
->Configure (Tcp6
, NULL
);
472 if ((Tcp4
!= NULL
) || (Tcp6
!= NULL
)) {
483 if (TcpIo
->IsListenDone
) {
484 if (TcpVersion
== TCP_VERSION_4
) {
485 Tcp4
= TcpIo
->NewTcp
.Tcp4
;
487 Tcp4
->Configure (Tcp4
, NULL
);
488 ChildHandle
= TcpIo
->ListenToken
.Tcp4Token
.NewChildHandle
;
491 Tcp6
= TcpIo
->NewTcp
.Tcp6
;
493 Tcp6
->Configure (Tcp6
, NULL
);
494 ChildHandle
= TcpIo
->ListenToken
.Tcp6Token
.NewChildHandle
;
498 if (ChildHandle
!= NULL
) {
508 NetLibDestroyServiceChild (
517 Connect to the other endpoint of the TCP socket.
519 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
520 @param[in] Timeout The time to wait for connection done. Set to NULL for infinite wait.
522 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket
524 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the
525 TCP socket in the specified time period.
526 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
527 @retval EFI_UNSUPPORTED One or more of the control options are not
528 supported in the implementation.
529 @retval Others Other errors as indicated.
535 IN OUT TCP_IO
*TcpIo
,
536 IN EFI_EVENT Timeout OPTIONAL
539 EFI_TCP4_PROTOCOL
*Tcp4
;
540 EFI_TCP6_PROTOCOL
*Tcp6
;
543 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)) {
544 return EFI_INVALID_PARAMETER
;
547 TcpIo
->IsConnDone
= FALSE
;
552 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
553 Tcp4
= TcpIo
->Tcp
.Tcp4
;
554 Status
= Tcp4
->Connect (Tcp4
, &TcpIo
->ConnToken
.Tcp4Token
);
555 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
556 Tcp6
= TcpIo
->Tcp
.Tcp6
;
557 Status
= Tcp6
->Connect (Tcp6
, &TcpIo
->ConnToken
.Tcp6Token
);
559 return EFI_UNSUPPORTED
;
562 if (EFI_ERROR (Status
)) {
566 while (!TcpIo
->IsConnDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
567 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
574 if (!TcpIo
->IsConnDone
) {
575 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
576 Tcp4
->Cancel (Tcp4
, &TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
);
578 Tcp6
->Cancel (Tcp6
, &TcpIo
->ConnToken
.Tcp6Token
.CompletionToken
);
581 Status
= EFI_TIMEOUT
;
583 Status
= TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
.Status
;
590 Accept the incomding request from the other endpoint of the TCP socket.
592 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
593 @param[in] Timeout The time to wait for connection done. Set to NULL for infinite wait.
596 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket
598 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
599 @retval EFI_UNSUPPORTED One or more of the control options are not
600 supported in the implementation.
602 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the
603 TCP socket in the specified time period.
604 @retval Others Other errors as indicated.
610 IN OUT TCP_IO
*TcpIo
,
611 IN EFI_EVENT Timeout OPTIONAL
615 EFI_GUID
*ProtocolGuid
;
616 EFI_TCP4_PROTOCOL
*Tcp4
;
617 EFI_TCP6_PROTOCOL
*Tcp6
;
619 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)) {
620 return EFI_INVALID_PARAMETER
;
623 TcpIo
->IsListenDone
= FALSE
;
628 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
629 Tcp4
= TcpIo
->Tcp
.Tcp4
;
630 Status
= Tcp4
->Accept (Tcp4
, &TcpIo
->ListenToken
.Tcp4Token
);
631 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
632 Tcp6
= TcpIo
->Tcp
.Tcp6
;
633 Status
= Tcp6
->Accept (Tcp6
, &TcpIo
->ListenToken
.Tcp6Token
);
635 return EFI_UNSUPPORTED
;
638 if (EFI_ERROR (Status
)) {
642 while (!TcpIo
->IsListenDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
643 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
650 if (!TcpIo
->IsListenDone
) {
651 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
652 Tcp4
->Cancel (Tcp4
, &TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
);
654 Tcp6
->Cancel (Tcp6
, &TcpIo
->ListenToken
.Tcp6Token
.CompletionToken
);
657 Status
= EFI_TIMEOUT
;
659 Status
= TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
.Status
;
663 // The new TCP instance handle created for the established connection is
666 if (!EFI_ERROR (Status
)) {
667 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
668 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
670 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
673 Status
= gBS
->OpenProtocol (
674 TcpIo
->ListenToken
.Tcp4Token
.NewChildHandle
,
676 (VOID
**)(&TcpIo
->NewTcp
.Tcp4
),
679 EFI_OPEN_PROTOCOL_BY_DRIVER
689 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
698 EFI_TCP4_PROTOCOL
*Tcp4
;
699 EFI_TCP6_PROTOCOL
*Tcp6
;
702 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)) {
706 TcpIo
->IsCloseDone
= FALSE
;
710 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
711 TcpIo
->CloseToken
.Tcp4Token
.AbortOnClose
= TRUE
;
712 Tcp4
= TcpIo
->Tcp
.Tcp4
;
713 Status
= Tcp4
->Close (Tcp4
, &TcpIo
->CloseToken
.Tcp4Token
);
714 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
715 TcpIo
->CloseToken
.Tcp6Token
.AbortOnClose
= TRUE
;
716 Tcp6
= TcpIo
->Tcp
.Tcp6
;
717 Status
= Tcp6
->Close (Tcp6
, &TcpIo
->CloseToken
.Tcp6Token
);
722 if (EFI_ERROR (Status
)) {
726 while (!TcpIo
->IsCloseDone
) {
727 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
736 Transmit the Packet to the other endpoint of the socket.
738 @param[in] TcpIo The TcpIo wrapping the TCP socket.
739 @param[in] Packet The packet to transmit.
741 @retval EFI_SUCCESS The packet is transmitted.
742 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
743 @retval EFI_UNSUPPORTED One or more of the control options are not
744 supported in the implementation.
745 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
746 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
747 @retval Others Other errors as indicated.
759 EFI_TCP4_PROTOCOL
*Tcp4
;
760 EFI_TCP6_PROTOCOL
*Tcp6
;
763 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
) || (Packet
== NULL
)) {
764 return EFI_INVALID_PARAMETER
;
767 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
768 Size
= sizeof (EFI_TCP4_TRANSMIT_DATA
) +
769 (Packet
->BlockOpNum
- 1) * sizeof (EFI_TCP4_FRAGMENT_DATA
);
770 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
771 Size
= sizeof (EFI_TCP6_TRANSMIT_DATA
) +
772 (Packet
->BlockOpNum
- 1) * sizeof (EFI_TCP6_FRAGMENT_DATA
);
774 return EFI_UNSUPPORTED
;
777 Data
= AllocatePool (Size
);
779 return EFI_OUT_OF_RESOURCES
;
782 ((EFI_TCP4_TRANSMIT_DATA
*)Data
)->Push
= TRUE
;
783 ((EFI_TCP4_TRANSMIT_DATA
*)Data
)->Urgent
= FALSE
;
784 ((EFI_TCP4_TRANSMIT_DATA
*)Data
)->DataLength
= Packet
->TotalSize
;
787 // Build the fragment table.
789 ((EFI_TCP4_TRANSMIT_DATA
*)Data
)->FragmentCount
= Packet
->BlockOpNum
;
793 (NET_FRAGMENT
*)&((EFI_TCP4_TRANSMIT_DATA
*)Data
)->FragmentTable
[0],
794 &((EFI_TCP4_TRANSMIT_DATA
*)Data
)->FragmentCount
799 Status
= EFI_DEVICE_ERROR
;
802 // Transmit the packet.
804 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
805 TcpIo
->TxToken
.Tcp4Token
.Packet
.TxData
= (EFI_TCP4_TRANSMIT_DATA
*)Data
;
806 Tcp4
= TcpIo
->Tcp
.Tcp4
;
807 if (TcpIo
->IsListenDone
) {
808 Tcp4
= TcpIo
->NewTcp
.Tcp4
;
815 Status
= Tcp4
->Transmit (Tcp4
, &TcpIo
->TxToken
.Tcp4Token
);
817 TcpIo
->TxToken
.Tcp6Token
.Packet
.TxData
= (EFI_TCP6_TRANSMIT_DATA
*)Data
;
818 Tcp6
= TcpIo
->Tcp
.Tcp6
;
819 if (TcpIo
->IsListenDone
) {
820 Tcp6
= TcpIo
->NewTcp
.Tcp6
;
827 Status
= Tcp6
->Transmit (Tcp6
, &TcpIo
->TxToken
.Tcp6Token
);
830 if (EFI_ERROR (Status
)) {
834 while (!TcpIo
->IsTxDone
) {
835 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
842 TcpIo
->IsTxDone
= FALSE
;
843 Status
= TcpIo
->TxToken
.Tcp4Token
.CompletionToken
.Status
;
853 Receive data from the socket.
855 @param[in, out] TcpIo The TcpIo which wraps the socket to be destroyed.
856 @param[in] Packet The buffer to hold the data copy from the socket rx buffer.
857 @param[in] AsyncMode Is this receive asynchronous or not.
858 @param[in] Timeout The time to wait for receiving the amount of data the Packet
859 can hold. Set to NULL for infinite wait.
861 @retval EFI_SUCCESS The required amount of data is received from the socket.
862 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
863 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
864 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
865 @retval EFI_TIMEOUT Failed to receive the required amount of data in the
866 specified time period.
867 @retval Others Other errors as indicated.
873 IN OUT TCP_IO
*TcpIo
,
875 IN BOOLEAN AsyncMode
,
876 IN EFI_EVENT Timeout OPTIONAL
879 EFI_TCP4_PROTOCOL
*Tcp4
;
880 EFI_TCP6_PROTOCOL
*Tcp6
;
881 EFI_TCP4_RECEIVE_DATA
*RxData
;
883 NET_FRAGMENT
*Fragment
;
884 UINT32 FragmentCount
;
885 UINT32 CurrentFragment
;
887 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
) || (Packet
== NULL
)) {
888 return EFI_INVALID_PARAMETER
;
891 RxData
= TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
;
892 if (RxData
== NULL
) {
893 return EFI_INVALID_PARAMETER
;
899 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
900 Tcp4
= TcpIo
->Tcp
.Tcp4
;
902 if (TcpIo
->IsListenDone
) {
903 Tcp4
= TcpIo
->NewTcp
.Tcp4
;
907 return EFI_DEVICE_ERROR
;
909 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
910 Tcp6
= TcpIo
->Tcp
.Tcp6
;
912 if (TcpIo
->IsListenDone
) {
913 Tcp6
= TcpIo
->NewTcp
.Tcp6
;
917 return EFI_DEVICE_ERROR
;
920 return EFI_UNSUPPORTED
;
923 FragmentCount
= Packet
->BlockOpNum
;
924 Fragment
= AllocatePool (FragmentCount
* sizeof (NET_FRAGMENT
));
925 if (Fragment
== NULL
) {
926 Status
= EFI_OUT_OF_RESOURCES
;
931 // Build the fragment table.
933 NetbufBuildExt (Packet
, Fragment
, &FragmentCount
);
935 RxData
->FragmentCount
= 1;
937 Status
= EFI_SUCCESS
;
939 while (CurrentFragment
< FragmentCount
) {
940 RxData
->DataLength
= Fragment
[CurrentFragment
].Len
;
941 RxData
->FragmentTable
[0].FragmentLength
= Fragment
[CurrentFragment
].Len
;
942 RxData
->FragmentTable
[0].FragmentBuffer
= Fragment
[CurrentFragment
].Bulk
;
944 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
945 Status
= Tcp4
->Receive (Tcp4
, &TcpIo
->RxToken
.Tcp4Token
);
947 Status
= Tcp6
->Receive (Tcp6
, &TcpIo
->RxToken
.Tcp6Token
);
950 if (EFI_ERROR (Status
)) {
954 while (!TcpIo
->IsRxDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
956 // Poll until some data is received or an error occurs.
958 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
965 if (!TcpIo
->IsRxDone
) {
967 // Timeout occurs, cancel the receive request.
969 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
970 Tcp4
->Cancel (Tcp4
, &TcpIo
->RxToken
.Tcp4Token
.CompletionToken
);
972 Tcp6
->Cancel (Tcp6
, &TcpIo
->RxToken
.Tcp6Token
.CompletionToken
);
975 Status
= EFI_TIMEOUT
;
978 TcpIo
->IsRxDone
= FALSE
;
981 Status
= TcpIo
->RxToken
.Tcp4Token
.CompletionToken
.Status
;
983 if (EFI_ERROR (Status
)) {
987 Fragment
[CurrentFragment
].Len
-= RxData
->FragmentTable
[0].FragmentLength
;
988 if (Fragment
[CurrentFragment
].Len
== 0) {
991 Fragment
[CurrentFragment
].Bulk
+= RxData
->FragmentTable
[0].FragmentLength
;
997 if (Fragment
!= NULL
) {