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
))) {
91 Status
= Tcp6
->Configure (Tcp6
, Tcp6ConfigData
);
93 if (!EFI_ERROR (Status
)) {
101 gBS
->CloseEvent (Event
);
108 Create a TCP socket with the specified configuration data.
110 @param[in] Image The handle of the driver image.
111 @param[in] Controller The handle of the controller.
112 @param[in] TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6.
113 @param[in] ConfigData The Tcp configuration data.
114 @param[out] TcpIo The TcpIo.
116 @retval EFI_SUCCESS The TCP socket is created and configured.
117 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
118 @retval EFI_UNSUPPORTED One or more of the control options are not
119 supported in the implementation.
120 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
121 @retval Others Failed to create the TCP socket or configure it.
128 IN EFI_HANDLE Controller
,
130 IN TCP_IO_CONFIG_DATA
*ConfigData
,
136 EFI_GUID
*ServiceBindingGuid
;
137 EFI_GUID
*ProtocolGuid
;
139 EFI_TCP4_OPTION ControlOption
;
140 EFI_TCP4_CONFIG_DATA Tcp4ConfigData
;
141 EFI_TCP4_ACCESS_POINT
*AccessPoint4
;
142 EFI_TCP4_PROTOCOL
*Tcp4
;
143 EFI_TCP6_CONFIG_DATA Tcp6ConfigData
;
144 EFI_TCP6_ACCESS_POINT
*AccessPoint6
;
145 EFI_TCP6_PROTOCOL
*Tcp6
;
146 EFI_TCP4_RECEIVE_DATA
*RxData
;
148 if ((Image
== NULL
) || (Controller
== NULL
) || (ConfigData
== NULL
) || (TcpIo
== NULL
)) {
149 return EFI_INVALID_PARAMETER
;
155 ZeroMem (TcpIo
, sizeof (TCP_IO
));
157 if (TcpVersion
== TCP_VERSION_4
) {
158 ServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
159 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
160 Interface
= (VOID
**) (&TcpIo
->Tcp
.Tcp4
);
161 } else if (TcpVersion
== TCP_VERSION_6
) {
162 ServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
163 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
164 Interface
= (VOID
**) (&TcpIo
->Tcp
.Tcp6
);
166 return EFI_UNSUPPORTED
;
169 TcpIo
->TcpVersion
= TcpVersion
;
172 // Create the TCP child instance and get the TCP protocol.
174 Status
= NetLibCreateServiceChild (
180 if (EFI_ERROR (Status
)) {
184 Status
= gBS
->OpenProtocol (
190 EFI_OPEN_PROTOCOL_BY_DRIVER
192 if (EFI_ERROR (Status
) || (*Interface
== NULL
)) {
196 if (TcpVersion
== TCP_VERSION_4
) {
197 Tcp4
= TcpIo
->Tcp
.Tcp4
;
199 Tcp6
= TcpIo
->Tcp
.Tcp6
;
202 TcpIo
->Image
= Image
;
203 TcpIo
->Controller
= Controller
;
206 // Set the configuration parameters.
208 ControlOption
.ReceiveBufferSize
= 0x200000;
209 ControlOption
.SendBufferSize
= 0x200000;
210 ControlOption
.MaxSynBackLog
= 0;
211 ControlOption
.ConnectionTimeout
= 0;
212 ControlOption
.DataRetries
= 6;
213 ControlOption
.FinTimeout
= 0;
214 ControlOption
.TimeWaitTimeout
= 0;
215 ControlOption
.KeepAliveProbes
= 4;
216 ControlOption
.KeepAliveTime
= 0;
217 ControlOption
.KeepAliveInterval
= 0;
218 ControlOption
.EnableNagle
= FALSE
;
219 ControlOption
.EnableTimeStamp
= FALSE
;
220 ControlOption
.EnableWindowScaling
= TRUE
;
221 ControlOption
.EnableSelectiveAck
= FALSE
;
222 ControlOption
.EnablePathMtuDiscovery
= FALSE
;
224 if (TcpVersion
== TCP_VERSION_4
) {
225 Tcp4ConfigData
.TypeOfService
= 8;
226 Tcp4ConfigData
.TimeToLive
= 255;
227 Tcp4ConfigData
.ControlOption
= &ControlOption
;
229 AccessPoint4
= &Tcp4ConfigData
.AccessPoint
;
231 ZeroMem (AccessPoint4
, sizeof (EFI_TCP4_ACCESS_POINT
));
232 AccessPoint4
->StationPort
= ConfigData
->Tcp4IoConfigData
.StationPort
;
233 AccessPoint4
->RemotePort
= ConfigData
->Tcp4IoConfigData
.RemotePort
;
234 AccessPoint4
->ActiveFlag
= ConfigData
->Tcp4IoConfigData
.ActiveFlag
;
237 &AccessPoint4
->StationAddress
,
238 &ConfigData
->Tcp4IoConfigData
.LocalIp
,
239 sizeof (EFI_IPv4_ADDRESS
)
242 &AccessPoint4
->SubnetMask
,
243 &ConfigData
->Tcp4IoConfigData
.SubnetMask
,
244 sizeof (EFI_IPv4_ADDRESS
)
247 &AccessPoint4
->RemoteAddress
,
248 &ConfigData
->Tcp4IoConfigData
.RemoteIp
,
249 sizeof (EFI_IPv4_ADDRESS
)
252 ASSERT (Tcp4
!= NULL
);
255 // Configure the TCP4 protocol.
257 Status
= Tcp4
->Configure (Tcp4
, &Tcp4ConfigData
);
258 if (EFI_ERROR (Status
)) {
262 if (!EFI_IP4_EQUAL (&ConfigData
->Tcp4IoConfigData
.Gateway
, &mZeroIp4Addr
)) {
264 // The gateway is not zero. Add the default route manually.
266 Status
= Tcp4
->Routes (
271 &ConfigData
->Tcp4IoConfigData
.Gateway
273 if (EFI_ERROR (Status
)) {
278 Tcp6ConfigData
.TrafficClass
= 0;
279 Tcp6ConfigData
.HopLimit
= 255;
280 Tcp6ConfigData
.ControlOption
= (EFI_TCP6_OPTION
*) &ControlOption
;
282 AccessPoint6
= &Tcp6ConfigData
.AccessPoint
;
284 ZeroMem (AccessPoint6
, sizeof (EFI_TCP6_ACCESS_POINT
));
285 AccessPoint6
->StationPort
= ConfigData
->Tcp6IoConfigData
.StationPort
;
286 AccessPoint6
->RemotePort
= ConfigData
->Tcp6IoConfigData
.RemotePort
;
287 AccessPoint6
->ActiveFlag
= ConfigData
->Tcp6IoConfigData
.ActiveFlag
;
289 IP6_COPY_ADDRESS (&AccessPoint6
->RemoteAddress
, &ConfigData
->Tcp6IoConfigData
.RemoteIp
);
292 ASSERT (Tcp6
!= NULL
);
294 // Configure the TCP6 protocol.
296 Status
= Tcp6
->Configure (Tcp6
, &Tcp6ConfigData
);
297 if (Status
== EFI_NO_MAPPING
) {
298 Status
= TcpIoGetMapping (Tcp6
, &Tcp6ConfigData
);
301 if (EFI_ERROR (Status
)) {
307 // Create events for various asynchronous operations.
309 Status
= gBS
->CreateEvent (
316 if (EFI_ERROR (Status
)) {
320 TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
322 Status
= gBS
->CreateEvent (
326 &TcpIo
->IsListenDone
,
329 if (EFI_ERROR (Status
)) {
333 TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
335 Status
= gBS
->CreateEvent (
342 if (EFI_ERROR (Status
)) {
346 TcpIo
->TxToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
349 Status
= gBS
->CreateEvent (
356 if (EFI_ERROR (Status
)) {
360 TcpIo
->RxToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
362 RxData
= (EFI_TCP4_RECEIVE_DATA
*) AllocateZeroPool (sizeof (EFI_TCP4_RECEIVE_DATA
));
363 if (RxData
== NULL
) {
364 Status
= EFI_OUT_OF_RESOURCES
;
368 TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
= RxData
;
370 Status
= gBS
->CreateEvent (
377 if (EFI_ERROR (Status
)) {
381 TcpIo
->CloseToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
388 TcpIoDestroySocket (TcpIo
);
396 @param[in] TcpIo The TcpIo which wraps the socket to be destroyed.
406 EFI_TCP4_PROTOCOL
*Tcp4
;
407 EFI_TCP6_PROTOCOL
*Tcp6
;
409 EFI_GUID
*ServiceBindingGuid
;
410 EFI_GUID
*ProtocolGuid
;
411 EFI_HANDLE ChildHandle
;
417 TcpVersion
= TcpIo
->TcpVersion
;
419 if ((TcpVersion
!= TCP_VERSION_4
) && (TcpVersion
!= TCP_VERSION_6
)) {
423 Event
= TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
.Event
;
426 gBS
->CloseEvent (Event
);
429 Event
= TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
.Event
;
432 gBS
->CloseEvent (Event
);
435 Event
= TcpIo
->TxToken
.Tcp4Token
.CompletionToken
.Event
;
438 gBS
->CloseEvent (Event
);
441 Event
= TcpIo
->RxToken
.Tcp4Token
.CompletionToken
.Event
;
444 gBS
->CloseEvent (Event
);
447 Event
= TcpIo
->CloseToken
.Tcp4Token
.CompletionToken
.Event
;
450 gBS
->CloseEvent (Event
);
453 if (TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
!= NULL
) {
454 FreePool (TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
);
461 if (TcpVersion
== TCP_VERSION_4
) {
462 ServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
463 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
464 Tcp4
= TcpIo
->Tcp
.Tcp4
;
466 Tcp4
->Configure (Tcp4
, NULL
);
469 ServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
470 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
471 Tcp6
= TcpIo
->Tcp
.Tcp6
;
473 Tcp6
->Configure (Tcp6
, NULL
);
477 if ((Tcp4
!= NULL
) || (Tcp6
!= NULL
)) {
489 if (TcpIo
->IsListenDone
) {
490 if (TcpVersion
== TCP_VERSION_4
) {
491 Tcp4
= TcpIo
->NewTcp
.Tcp4
;
493 Tcp4
->Configure (Tcp4
, NULL
);
494 ChildHandle
= TcpIo
->ListenToken
.Tcp4Token
.NewChildHandle
;
497 Tcp6
= TcpIo
->NewTcp
.Tcp6
;
499 Tcp6
->Configure (Tcp6
, NULL
);
500 ChildHandle
= TcpIo
->ListenToken
.Tcp6Token
.NewChildHandle
;
504 if (ChildHandle
!= NULL
) {
515 NetLibDestroyServiceChild (
524 Connect to the other endpoint of the TCP socket.
526 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
527 @param[in] Timeout The time to wait for connection done. Set to NULL for infinite wait.
529 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket
531 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the
532 TCP socket in the specified time period.
533 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
534 @retval EFI_UNSUPPORTED One or more of the control options are not
535 supported in the implementation.
536 @retval Others Other errors as indicated.
542 IN OUT TCP_IO
*TcpIo
,
543 IN EFI_EVENT Timeout OPTIONAL
546 EFI_TCP4_PROTOCOL
*Tcp4
;
547 EFI_TCP6_PROTOCOL
*Tcp6
;
550 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)) {
551 return EFI_INVALID_PARAMETER
;
554 TcpIo
->IsConnDone
= FALSE
;
559 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
560 Tcp4
= TcpIo
->Tcp
.Tcp4
;
561 Status
= Tcp4
->Connect (Tcp4
, &TcpIo
->ConnToken
.Tcp4Token
);
562 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
563 Tcp6
= TcpIo
->Tcp
.Tcp6
;
564 Status
= Tcp6
->Connect (Tcp6
, &TcpIo
->ConnToken
.Tcp6Token
);
566 return EFI_UNSUPPORTED
;
569 if (EFI_ERROR (Status
)) {
573 while (!TcpIo
->IsConnDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
574 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
581 if (!TcpIo
->IsConnDone
) {
582 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
583 Tcp4
->Cancel (Tcp4
, &TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
);
585 Tcp6
->Cancel (Tcp6
, &TcpIo
->ConnToken
.Tcp6Token
.CompletionToken
);
587 Status
= EFI_TIMEOUT
;
589 Status
= TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
.Status
;
596 Accept the incomding request from the other endpoint of the TCP socket.
598 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
599 @param[in] Timeout The time to wait for connection done. Set to NULL for infinite wait.
602 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket
604 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
605 @retval EFI_UNSUPPORTED One or more of the control options are not
606 supported in the implementation.
608 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the
609 TCP socket in the specified time period.
610 @retval Others Other errors as indicated.
616 IN OUT TCP_IO
*TcpIo
,
617 IN EFI_EVENT Timeout OPTIONAL
621 EFI_GUID
*ProtocolGuid
;
622 EFI_TCP4_PROTOCOL
*Tcp4
;
623 EFI_TCP6_PROTOCOL
*Tcp6
;
625 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)) {
626 return EFI_INVALID_PARAMETER
;
629 TcpIo
->IsListenDone
= FALSE
;
634 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
635 Tcp4
= TcpIo
->Tcp
.Tcp4
;
636 Status
= Tcp4
->Accept (Tcp4
, &TcpIo
->ListenToken
.Tcp4Token
);
637 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
638 Tcp6
= TcpIo
->Tcp
.Tcp6
;
639 Status
= Tcp6
->Accept (Tcp6
, &TcpIo
->ListenToken
.Tcp6Token
);
641 return EFI_UNSUPPORTED
;
644 if (EFI_ERROR (Status
)) {
648 while (!TcpIo
->IsListenDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
649 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
656 if (!TcpIo
->IsListenDone
) {
657 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
658 Tcp4
->Cancel (Tcp4
, &TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
);
660 Tcp6
->Cancel (Tcp6
, &TcpIo
->ListenToken
.Tcp6Token
.CompletionToken
);
662 Status
= EFI_TIMEOUT
;
664 Status
= TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
.Status
;
668 // The new TCP instance handle created for the established connection is
671 if (!EFI_ERROR (Status
)) {
672 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
673 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
675 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
678 Status
= gBS
->OpenProtocol (
679 TcpIo
->ListenToken
.Tcp4Token
.NewChildHandle
,
681 (VOID
**) (&TcpIo
->NewTcp
.Tcp4
),
684 EFI_OPEN_PROTOCOL_BY_DRIVER
695 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
704 EFI_TCP4_PROTOCOL
*Tcp4
;
705 EFI_TCP6_PROTOCOL
*Tcp6
;
708 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)) {
712 TcpIo
->IsCloseDone
= FALSE
;
716 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
717 TcpIo
->CloseToken
.Tcp4Token
.AbortOnClose
= TRUE
;
718 Tcp4
= TcpIo
->Tcp
.Tcp4
;
719 Status
= Tcp4
->Close (Tcp4
, &TcpIo
->CloseToken
.Tcp4Token
);
720 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
721 TcpIo
->CloseToken
.Tcp6Token
.AbortOnClose
= TRUE
;
722 Tcp6
= TcpIo
->Tcp
.Tcp6
;
723 Status
= Tcp6
->Close (Tcp6
, &TcpIo
->CloseToken
.Tcp6Token
);
728 if (EFI_ERROR (Status
)) {
732 while (!TcpIo
->IsCloseDone
) {
733 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
743 Transmit the Packet to the other endpoint of the socket.
745 @param[in] TcpIo The TcpIo wrapping the TCP socket.
746 @param[in] Packet The packet to transmit.
748 @retval EFI_SUCCESS The packet is transmitted.
749 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
750 @retval EFI_UNSUPPORTED One or more of the control options are not
751 supported in the implementation.
752 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
753 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
754 @retval Others Other errors as indicated.
766 EFI_TCP4_PROTOCOL
*Tcp4
;
767 EFI_TCP6_PROTOCOL
*Tcp6
;
770 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)|| (Packet
== NULL
)) {
771 return EFI_INVALID_PARAMETER
;
774 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
776 Size
= sizeof (EFI_TCP4_TRANSMIT_DATA
) +
777 (Packet
->BlockOpNum
- 1) * sizeof (EFI_TCP4_FRAGMENT_DATA
);
778 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
779 Size
= sizeof (EFI_TCP6_TRANSMIT_DATA
) +
780 (Packet
->BlockOpNum
- 1) * sizeof (EFI_TCP6_FRAGMENT_DATA
);
782 return EFI_UNSUPPORTED
;
785 Data
= AllocatePool (Size
);
787 return EFI_OUT_OF_RESOURCES
;
790 ((EFI_TCP4_TRANSMIT_DATA
*) Data
)->Push
= TRUE
;
791 ((EFI_TCP4_TRANSMIT_DATA
*) Data
)->Urgent
= FALSE
;
792 ((EFI_TCP4_TRANSMIT_DATA
*) Data
)->DataLength
= Packet
->TotalSize
;
795 // Build the fragment table.
797 ((EFI_TCP4_TRANSMIT_DATA
*) Data
)->FragmentCount
= Packet
->BlockOpNum
;
801 (NET_FRAGMENT
*) &((EFI_TCP4_TRANSMIT_DATA
*) Data
)->FragmentTable
[0],
802 &((EFI_TCP4_TRANSMIT_DATA
*) Data
)->FragmentCount
807 Status
= EFI_DEVICE_ERROR
;
810 // Transmit the packet.
812 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
813 TcpIo
->TxToken
.Tcp4Token
.Packet
.TxData
= (EFI_TCP4_TRANSMIT_DATA
*) Data
;
814 Tcp4
= TcpIo
->Tcp
.Tcp4
;
815 if (TcpIo
->IsListenDone
) {
816 Tcp4
= TcpIo
->NewTcp
.Tcp4
;
823 Status
= Tcp4
->Transmit (Tcp4
, &TcpIo
->TxToken
.Tcp4Token
);
825 TcpIo
->TxToken
.Tcp6Token
.Packet
.TxData
= (EFI_TCP6_TRANSMIT_DATA
*) Data
;
826 Tcp6
= TcpIo
->Tcp
.Tcp6
;
827 if (TcpIo
->IsListenDone
) {
828 Tcp6
= TcpIo
->NewTcp
.Tcp6
;
835 Status
= Tcp6
->Transmit (Tcp6
, &TcpIo
->TxToken
.Tcp6Token
);
838 if (EFI_ERROR (Status
)) {
842 while (!TcpIo
->IsTxDone
) {
843 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
850 TcpIo
->IsTxDone
= FALSE
;
851 Status
= TcpIo
->TxToken
.Tcp4Token
.CompletionToken
.Status
;
861 Receive data from the socket.
863 @param[in, out] TcpIo The TcpIo which wraps the socket to be destroyed.
864 @param[in] Packet The buffer to hold the data copy from the socket rx buffer.
865 @param[in] AsyncMode Is this receive asynchronous or not.
866 @param[in] Timeout The time to wait for receiving the amount of data the Packet
867 can hold. Set to NULL for infinite wait.
869 @retval EFI_SUCCESS The required amount of data is received from the socket.
870 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
871 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
872 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
873 @retval EFI_TIMEOUT Failed to receive the required amount of data in the
874 specified time period.
875 @retval Others Other errors as indicated.
881 IN OUT TCP_IO
*TcpIo
,
883 IN BOOLEAN AsyncMode
,
884 IN EFI_EVENT Timeout OPTIONAL
887 EFI_TCP4_PROTOCOL
*Tcp4
;
888 EFI_TCP6_PROTOCOL
*Tcp6
;
889 EFI_TCP4_RECEIVE_DATA
*RxData
;
891 NET_FRAGMENT
*Fragment
;
892 UINT32 FragmentCount
;
893 UINT32 CurrentFragment
;
895 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)|| (Packet
== NULL
)) {
896 return EFI_INVALID_PARAMETER
;
899 RxData
= TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
;
900 if (RxData
== NULL
) {
901 return EFI_INVALID_PARAMETER
;
907 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
908 Tcp4
= TcpIo
->Tcp
.Tcp4
;
910 if (TcpIo
->IsListenDone
) {
911 Tcp4
= TcpIo
->NewTcp
.Tcp4
;
915 return EFI_DEVICE_ERROR
;
918 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
919 Tcp6
= TcpIo
->Tcp
.Tcp6
;
921 if (TcpIo
->IsListenDone
) {
922 Tcp6
= TcpIo
->NewTcp
.Tcp6
;
926 return EFI_DEVICE_ERROR
;
930 return EFI_UNSUPPORTED
;
933 FragmentCount
= Packet
->BlockOpNum
;
934 Fragment
= AllocatePool (FragmentCount
* sizeof (NET_FRAGMENT
));
935 if (Fragment
== NULL
) {
936 Status
= EFI_OUT_OF_RESOURCES
;
940 // Build the fragment table.
942 NetbufBuildExt (Packet
, Fragment
, &FragmentCount
);
944 RxData
->FragmentCount
= 1;
946 Status
= EFI_SUCCESS
;
948 while (CurrentFragment
< FragmentCount
) {
949 RxData
->DataLength
= Fragment
[CurrentFragment
].Len
;
950 RxData
->FragmentTable
[0].FragmentLength
= Fragment
[CurrentFragment
].Len
;
951 RxData
->FragmentTable
[0].FragmentBuffer
= Fragment
[CurrentFragment
].Bulk
;
953 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
954 Status
= Tcp4
->Receive (Tcp4
, &TcpIo
->RxToken
.Tcp4Token
);
956 Status
= Tcp6
->Receive (Tcp6
, &TcpIo
->RxToken
.Tcp6Token
);
959 if (EFI_ERROR (Status
)) {
963 while (!TcpIo
->IsRxDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
965 // Poll until some data is received or an error occurs.
967 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
974 if (!TcpIo
->IsRxDone
) {
976 // Timeout occurs, cancel the receive request.
978 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
979 Tcp4
->Cancel (Tcp4
, &TcpIo
->RxToken
.Tcp4Token
.CompletionToken
);
981 Tcp6
->Cancel (Tcp6
, &TcpIo
->RxToken
.Tcp6Token
.CompletionToken
);
984 Status
= EFI_TIMEOUT
;
987 TcpIo
->IsRxDone
= FALSE
;
990 Status
= TcpIo
->RxToken
.Tcp4Token
.CompletionToken
.Status
;
992 if (EFI_ERROR (Status
)) {
996 Fragment
[CurrentFragment
].Len
-= RxData
->FragmentTable
[0].FragmentLength
;
997 if (Fragment
[CurrentFragment
].Len
== 0) {
1000 Fragment
[CurrentFragment
].Bulk
+= RxData
->FragmentTable
[0].FragmentLength
;
1006 if (Fragment
!= NULL
) {
1007 FreePool (Fragment
);