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, 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<BR>
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 #include <Library/TcpIoLib.h>
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/BaseMemoryLib.h>
26 The common notify function associated with various TcpIo events.
28 @param[in] Event The event signaled.
29 @param[in] Context The context.
39 if ((Event
== NULL
) || (Context
== NULL
)) {
43 *((BOOLEAN
*) Context
) = TRUE
;
47 The internal function for delay configuring TCP6 when IP6 driver is still in DAD.
49 @param[in] Tcp6 The EFI_TCP6_PROTOCOL protocol instance.
50 @param[in] Tcp6ConfigData The Tcp6 configuration data.
52 @retval EFI_SUCCESS The operational settings successfully
54 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
55 @retval Others Failed to finish the operation.
60 IN EFI_TCP6_PROTOCOL
*Tcp6
,
61 IN EFI_TCP6_CONFIG_DATA
*Tcp6ConfigData
67 if ((Tcp6
== NULL
) || (Tcp6ConfigData
== NULL
)) {
68 return EFI_INVALID_PARAMETER
;
72 Status
= gBS
->CreateEvent (
79 if (EFI_ERROR (Status
)) {
83 Status
= gBS
->SetTimer (
86 TCP_GET_MAPPING_TIMEOUT
89 if (EFI_ERROR (Status
)) {
93 while (EFI_ERROR (gBS
->CheckEvent (Event
))) {
97 Status
= Tcp6
->Configure (Tcp6
, Tcp6ConfigData
);
99 if (!EFI_ERROR (Status
)) {
107 gBS
->CloseEvent (Event
);
114 Create a TCP socket with the specified configuration data.
116 @param[in] Image The handle of the driver image.
117 @param[in] Controller The handle of the controller.
118 @param[in] TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6.
119 @param[in] ConfigData The Tcp configuration data.
120 @param[out] TcpIo The TcpIo.
122 @retval EFI_SUCCESS The TCP socket is created and configured.
123 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
124 @retval EFI_UNSUPPORTED One or more of the control options are not
125 supported in the implementation.
126 @retval Others Failed to create the TCP socket or configure it.
133 IN EFI_HANDLE Controller
,
135 IN TCP_IO_CONFIG_DATA
*ConfigData
,
141 EFI_GUID
*ServiceBindingGuid
;
142 EFI_GUID
*ProtocolGuid
;
144 EFI_TCP4_OPTION ControlOption
;
145 EFI_TCP4_CONFIG_DATA Tcp4ConfigData
;
146 EFI_TCP4_ACCESS_POINT
*AccessPoint4
;
147 EFI_TCP4_PROTOCOL
*Tcp4
;
148 EFI_TCP6_CONFIG_DATA Tcp6ConfigData
;
149 EFI_TCP6_ACCESS_POINT
*AccessPoint6
;
150 EFI_TCP6_PROTOCOL
*Tcp6
;
152 if ((Image
== NULL
) || (Controller
== NULL
) || (ConfigData
== NULL
) || (TcpIo
== NULL
)) {
153 return EFI_INVALID_PARAMETER
;
159 ZeroMem (TcpIo
, sizeof (TCP_IO
));
161 if (TcpVersion
== TCP_VERSION_4
) {
162 ServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
163 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
164 Interface
= (VOID
**) (&TcpIo
->Tcp
.Tcp4
);
165 } else if (TcpVersion
== TCP_VERSION_6
) {
166 ServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
167 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
168 Interface
= (VOID
**) (&TcpIo
->Tcp
.Tcp6
);
170 return EFI_UNSUPPORTED
;
173 TcpIo
->TcpVersion
= TcpVersion
;
176 // Create the TCP child instance and get the TCP protocol.
178 Status
= NetLibCreateServiceChild (
184 if (EFI_ERROR (Status
)) {
188 Status
= gBS
->OpenProtocol (
194 EFI_OPEN_PROTOCOL_BY_DRIVER
196 if (EFI_ERROR (Status
) || (*Interface
== NULL
)) {
200 if (TcpVersion
== TCP_VERSION_4
) {
201 Tcp4
= TcpIo
->Tcp
.Tcp4
;
203 Tcp6
= TcpIo
->Tcp
.Tcp6
;
206 TcpIo
->Image
= Image
;
207 TcpIo
->Controller
= Controller
;
210 // Set the configuration parameters.
212 ControlOption
.ReceiveBufferSize
= 0x200000;
213 ControlOption
.SendBufferSize
= 0x200000;
214 ControlOption
.MaxSynBackLog
= 0;
215 ControlOption
.ConnectionTimeout
= 0;
216 ControlOption
.DataRetries
= 6;
217 ControlOption
.FinTimeout
= 0;
218 ControlOption
.TimeWaitTimeout
= 0;
219 ControlOption
.KeepAliveProbes
= 4;
220 ControlOption
.KeepAliveTime
= 0;
221 ControlOption
.KeepAliveInterval
= 0;
222 ControlOption
.EnableNagle
= FALSE
;
223 ControlOption
.EnableTimeStamp
= FALSE
;
224 ControlOption
.EnableWindowScaling
= TRUE
;
225 ControlOption
.EnableSelectiveAck
= FALSE
;
226 ControlOption
.EnablePathMtuDiscovery
= FALSE
;
228 if (TcpVersion
== TCP_VERSION_4
) {
229 Tcp4ConfigData
.TypeOfService
= 8;
230 Tcp4ConfigData
.TimeToLive
= 255;
231 Tcp4ConfigData
.ControlOption
= &ControlOption
;
233 AccessPoint4
= &Tcp4ConfigData
.AccessPoint
;
235 ZeroMem (AccessPoint4
, sizeof (EFI_TCP4_ACCESS_POINT
));
236 AccessPoint4
->StationPort
= ConfigData
->Tcp4IoConfigData
.StationPort
;
237 AccessPoint4
->RemotePort
= ConfigData
->Tcp4IoConfigData
.RemotePort
;
238 AccessPoint4
->ActiveFlag
= ConfigData
->Tcp4IoConfigData
.ActiveFlag
;
241 &AccessPoint4
->StationAddress
,
242 &ConfigData
->Tcp4IoConfigData
.LocalIp
,
243 sizeof (EFI_IPv4_ADDRESS
)
246 &AccessPoint4
->SubnetMask
,
247 &ConfigData
->Tcp4IoConfigData
.SubnetMask
,
248 sizeof (EFI_IPv4_ADDRESS
)
251 &AccessPoint4
->RemoteAddress
,
252 &ConfigData
->Tcp4IoConfigData
.RemoteIp
,
253 sizeof (EFI_IPv4_ADDRESS
)
256 ASSERT (Tcp4
!= NULL
);
259 // Configure the TCP4 protocol.
261 Status
= Tcp4
->Configure (Tcp4
, &Tcp4ConfigData
);
262 if (EFI_ERROR (Status
)) {
266 if (!EFI_IP4_EQUAL (&ConfigData
->Tcp4IoConfigData
.Gateway
, &mZeroIp4Addr
)) {
268 // The gateway is not zero. Add the default route manually.
270 Status
= Tcp4
->Routes (
275 &ConfigData
->Tcp4IoConfigData
.Gateway
277 if (EFI_ERROR (Status
)) {
282 Tcp6ConfigData
.TrafficClass
= 0;
283 Tcp6ConfigData
.HopLimit
= 255;
284 Tcp6ConfigData
.ControlOption
= (EFI_TCP6_OPTION
*) &ControlOption
;
286 AccessPoint6
= &Tcp6ConfigData
.AccessPoint
;
288 ZeroMem (AccessPoint6
, sizeof (EFI_TCP6_ACCESS_POINT
));
289 AccessPoint6
->StationPort
= ConfigData
->Tcp6IoConfigData
.StationPort
;
290 AccessPoint6
->RemotePort
= ConfigData
->Tcp6IoConfigData
.RemotePort
;
291 AccessPoint6
->ActiveFlag
= ConfigData
->Tcp6IoConfigData
.ActiveFlag
;
293 IP6_COPY_ADDRESS (&AccessPoint6
->RemoteAddress
, &ConfigData
->Tcp6IoConfigData
.RemoteIp
);
296 ASSERT (Tcp6
!= NULL
);
298 // Configure the TCP6 protocol.
300 Status
= Tcp6
->Configure (Tcp6
, &Tcp6ConfigData
);
301 if (Status
== EFI_NO_MAPPING
) {
302 Status
= TcpIoGetMapping (Tcp6
, &Tcp6ConfigData
);
305 if (EFI_ERROR (Status
)) {
311 // Create events for variuos asynchronous operations.
313 Status
= gBS
->CreateEvent (
320 if (EFI_ERROR (Status
)) {
324 TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
326 Status
= gBS
->CreateEvent (
330 &TcpIo
->IsListenDone
,
333 if (EFI_ERROR (Status
)) {
337 TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
339 Status
= gBS
->CreateEvent (
346 if (EFI_ERROR (Status
)) {
350 TcpIo
->TxToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
353 Status
= gBS
->CreateEvent (
360 if (EFI_ERROR (Status
)) {
364 TcpIo
->RxToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
366 Status
= gBS
->CreateEvent (
373 if (EFI_ERROR (Status
)) {
377 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
);
453 if (TcpVersion
== TCP_VERSION_4
) {
454 ServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
455 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
456 Tcp4
= TcpIo
->Tcp
.Tcp4
;
458 Tcp4
->Configure (Tcp4
, NULL
);
461 ServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
462 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
463 Tcp6
= TcpIo
->Tcp
.Tcp6
;
465 Tcp6
->Configure (Tcp6
, NULL
);
469 if ((Tcp4
!= NULL
) || (Tcp6
!= NULL
)) {
481 if (TcpIo
->IsListenDone
) {
482 if (TcpVersion
== TCP_VERSION_4
) {
483 Tcp4
= TcpIo
->NewTcp
.Tcp4
;
485 Tcp4
->Configure (Tcp4
, NULL
);
486 ChildHandle
= TcpIo
->ListenToken
.Tcp4Token
.NewChildHandle
;
489 Tcp6
= TcpIo
->NewTcp
.Tcp6
;
491 Tcp6
->Configure (Tcp6
, NULL
);
492 ChildHandle
= TcpIo
->ListenToken
.Tcp6Token
.NewChildHandle
;
496 if (ChildHandle
!= NULL
) {
507 NetLibDestroyServiceChild (
516 Connect to the other endpoint of the TCP socket.
518 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
519 @param[in] Timeout The time to wait for connection done.
521 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket
523 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the
524 TCP socket in the specified time period.
525 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
526 @retval EFI_UNSUPPORTED One or more of the control options are not
527 supported in the implementation.
528 @retval Others Other errors as indicated.
534 IN OUT TCP_IO
*TcpIo
,
538 EFI_TCP4_PROTOCOL
*Tcp4
;
539 EFI_TCP6_PROTOCOL
*Tcp6
;
542 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)) {
543 return EFI_INVALID_PARAMETER
;
546 TcpIo
->IsConnDone
= FALSE
;
551 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
552 Tcp4
= TcpIo
->Tcp
.Tcp4
;
553 Status
= Tcp4
->Connect (Tcp4
, &TcpIo
->ConnToken
.Tcp4Token
);
554 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
555 Tcp6
= TcpIo
->Tcp
.Tcp6
;
556 Status
= Tcp6
->Connect (Tcp6
, &TcpIo
->ConnToken
.Tcp6Token
);
558 return EFI_UNSUPPORTED
;
561 if (EFI_ERROR (Status
)) {
565 while (!TcpIo
->IsConnDone
&& EFI_ERROR (gBS
->CheckEvent (Timeout
))) {
566 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
573 if (!TcpIo
->IsConnDone
) {
574 Status
= EFI_TIMEOUT
;
576 Status
= TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
.Status
;
583 Accept the incomding request from the other endpoint of the TCP socket.
585 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
586 @param[in] Timeout The time to wait for connection done.
589 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket
591 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
592 @retval EFI_UNSUPPORTED One or more of the control options are not
593 supported in the implementation.
595 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the
596 TCP socket in the specified time period.
597 @retval Others Other errors as indicated.
603 IN OUT TCP_IO
*TcpIo
,
608 EFI_GUID
*ProtocolGuid
;
609 EFI_TCP4_PROTOCOL
*Tcp4
;
610 EFI_TCP6_PROTOCOL
*Tcp6
;
612 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)) {
613 return EFI_INVALID_PARAMETER
;
616 TcpIo
->IsListenDone
= FALSE
;
621 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
622 Tcp4
= TcpIo
->Tcp
.Tcp4
;
623 Status
= Tcp4
->Accept (Tcp4
, &TcpIo
->ListenToken
.Tcp4Token
);
624 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
625 Tcp6
= TcpIo
->Tcp
.Tcp6
;
626 Status
= Tcp6
->Accept (Tcp6
, &TcpIo
->ListenToken
.Tcp6Token
);
628 return EFI_UNSUPPORTED
;
631 if (EFI_ERROR (Status
)) {
635 while (!TcpIo
->IsListenDone
&& EFI_ERROR (gBS
->CheckEvent (Timeout
))) {
636 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
643 if (!TcpIo
->IsListenDone
) {
644 Status
= EFI_TIMEOUT
;
646 Status
= TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
.Status
;
650 // The new TCP instance handle created for the established connection is
653 if (!EFI_ERROR (Status
)) {
654 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
655 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
657 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
660 Status
= gBS
->OpenProtocol (
661 TcpIo
->ListenToken
.Tcp4Token
.NewChildHandle
,
663 (VOID
**) (&TcpIo
->NewTcp
.Tcp4
),
666 EFI_OPEN_PROTOCOL_BY_DRIVER
677 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
686 EFI_TCP4_PROTOCOL
*Tcp4
;
687 EFI_TCP6_PROTOCOL
*Tcp6
;
690 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)) {
694 TcpIo
->IsCloseDone
= FALSE
;
698 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
699 TcpIo
->CloseToken
.Tcp4Token
.AbortOnClose
= TRUE
;
700 Tcp4
= TcpIo
->Tcp
.Tcp4
;
701 Status
= Tcp4
->Close (Tcp4
, &TcpIo
->CloseToken
.Tcp4Token
);
702 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
703 TcpIo
->CloseToken
.Tcp6Token
.AbortOnClose
= TRUE
;
704 Tcp6
= TcpIo
->Tcp
.Tcp6
;
705 Status
= Tcp6
->Close (Tcp6
, &TcpIo
->CloseToken
.Tcp6Token
);
710 if (EFI_ERROR (Status
)) {
714 while (!TcpIo
->IsCloseDone
) {
715 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
725 Transmit the Packet to the other endpoint of the socket.
727 @param[in] TcpIo The TcpIo wrapping the TCP socket.
728 @param[in] Packet The packet to transmit.
730 @retval EFI_SUCCESS The packet is trasmitted.
731 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
732 @retval EFI_UNSUPPORTED One or more of the control options are not
733 supported in the implementation.
734 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
735 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
736 @retval Others Other errors as indicated.
748 EFI_TCP4_PROTOCOL
*Tcp4
;
749 EFI_TCP6_PROTOCOL
*Tcp6
;
752 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)|| (Packet
== NULL
)) {
753 return EFI_INVALID_PARAMETER
;
756 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
758 Size
= sizeof (EFI_TCP4_TRANSMIT_DATA
) +
759 (Packet
->BlockOpNum
- 1) * sizeof (EFI_TCP4_FRAGMENT_DATA
);
760 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
761 Size
= sizeof (EFI_TCP6_TRANSMIT_DATA
) +
762 (Packet
->BlockOpNum
- 1) * sizeof (EFI_TCP6_FRAGMENT_DATA
);
764 return EFI_UNSUPPORTED
;
767 Data
= AllocatePool (Size
);
769 return EFI_OUT_OF_RESOURCES
;
772 ((EFI_TCP4_TRANSMIT_DATA
*) Data
)->Push
= TRUE
;
773 ((EFI_TCP4_TRANSMIT_DATA
*) Data
)->Urgent
= FALSE
;
774 ((EFI_TCP4_TRANSMIT_DATA
*) Data
)->DataLength
= Packet
->TotalSize
;
777 // Build the fragment table.
779 ((EFI_TCP4_TRANSMIT_DATA
*) Data
)->FragmentCount
= Packet
->BlockOpNum
;
783 (NET_FRAGMENT
*) &((EFI_TCP4_TRANSMIT_DATA
*) Data
)->FragmentTable
[0],
784 &((EFI_TCP4_TRANSMIT_DATA
*) Data
)->FragmentCount
789 Status
= EFI_DEVICE_ERROR
;
792 // Trasnmit the packet.
794 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
795 TcpIo
->TxToken
.Tcp4Token
.Packet
.TxData
= (EFI_TCP4_TRANSMIT_DATA
*) Data
;
796 Tcp4
= TcpIo
->Tcp
.Tcp4
;
797 if (TcpIo
->IsListenDone
) {
798 Tcp4
= TcpIo
->NewTcp
.Tcp4
;
805 Status
= Tcp4
->Transmit (Tcp4
, &TcpIo
->TxToken
.Tcp4Token
);
807 TcpIo
->TxToken
.Tcp6Token
.Packet
.TxData
= (EFI_TCP6_TRANSMIT_DATA
*) Data
;
808 Tcp6
= TcpIo
->Tcp
.Tcp6
;
809 if (TcpIo
->IsListenDone
) {
810 Tcp6
= TcpIo
->NewTcp
.Tcp6
;
817 Status
= Tcp6
->Transmit (Tcp6
, &TcpIo
->TxToken
.Tcp6Token
);
820 if (EFI_ERROR (Status
)) {
824 while (!TcpIo
->IsTxDone
) {
825 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
832 TcpIo
->IsTxDone
= FALSE
;
833 Status
= TcpIo
->TxToken
.Tcp4Token
.CompletionToken
.Status
;
843 Receive data from the socket.
845 @param[in, out] TcpIo The TcpIo which wraps the socket to be destroyed.
846 @param[in] Packet The buffer to hold the data copy from the socket rx buffer.
847 @param[in] AsyncMode Is this receive asyncronous or not.
848 @param[in] Timeout The time to wait for receiving the amount of data the Packet
851 @retval EFI_SUCCESS The required amount of data is received from the socket.
852 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
853 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
854 @retval EFI_OUT_OF_RESOURCES Failed to allocate momery.
855 @retval EFI_TIMEOUT Failed to receive the required amount of data in the
856 specified time period.
857 @retval Others Other errors as indicated.
863 IN OUT TCP_IO
*TcpIo
,
865 IN BOOLEAN AsyncMode
,
869 EFI_TCP4_PROTOCOL
*Tcp4
;
870 EFI_TCP6_PROTOCOL
*Tcp6
;
871 EFI_TCP4_RECEIVE_DATA RxData
;
873 NET_FRAGMENT
*Fragment
;
874 UINT32 FragmentCount
;
875 UINT32 CurrentFragment
;
877 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)|| (Packet
== NULL
)) {
878 return EFI_INVALID_PARAMETER
;
884 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
885 Tcp4
= TcpIo
->Tcp
.Tcp4
;
887 if (TcpIo
->IsListenDone
) {
888 Tcp4
= TcpIo
->NewTcp
.Tcp4
;
892 return EFI_DEVICE_ERROR
;
895 TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
= &RxData
;
897 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
898 Tcp6
= TcpIo
->Tcp
.Tcp6
;
900 if (TcpIo
->IsListenDone
) {
901 Tcp6
= TcpIo
->NewTcp
.Tcp6
;
905 return EFI_DEVICE_ERROR
;
908 TcpIo
->RxToken
.Tcp6Token
.Packet
.RxData
= (EFI_TCP6_RECEIVE_DATA
*) &RxData
;
911 return EFI_UNSUPPORTED
;
914 FragmentCount
= Packet
->BlockOpNum
;
915 Fragment
= AllocatePool (FragmentCount
* sizeof (NET_FRAGMENT
));
916 if (Fragment
== NULL
) {
917 Status
= EFI_OUT_OF_RESOURCES
;
921 // Build the fragment table.
923 NetbufBuildExt (Packet
, Fragment
, &FragmentCount
);
925 RxData
.FragmentCount
= 1;
927 Status
= EFI_SUCCESS
;
929 while (CurrentFragment
< FragmentCount
) {
930 RxData
.DataLength
= Fragment
[CurrentFragment
].Len
;
931 RxData
.FragmentTable
[0].FragmentLength
= Fragment
[CurrentFragment
].Len
;
932 RxData
.FragmentTable
[0].FragmentBuffer
= Fragment
[CurrentFragment
].Bulk
;
934 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
935 Status
= Tcp4
->Receive (Tcp4
, &TcpIo
->RxToken
.Tcp4Token
);
937 Status
= Tcp6
->Receive (Tcp6
, &TcpIo
->RxToken
.Tcp6Token
);
940 if (EFI_ERROR (Status
)) {
944 while (!TcpIo
->IsRxDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
946 // Poll until some data is received or an error occurs.
948 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
955 if (!TcpIo
->IsRxDone
) {
957 // Timeout occurs, cancel the receive request.
959 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
960 Tcp4
->Cancel (Tcp4
, &TcpIo
->RxToken
.Tcp4Token
.CompletionToken
);
962 Tcp6
->Cancel (Tcp6
, &TcpIo
->RxToken
.Tcp6Token
.CompletionToken
);
965 Status
= EFI_TIMEOUT
;
968 TcpIo
->IsRxDone
= FALSE
;
971 Status
= TcpIo
->RxToken
.Tcp4Token
.CompletionToken
.Status
;
973 if (EFI_ERROR (Status
)) {
977 Fragment
[CurrentFragment
].Len
-= RxData
.FragmentTable
[0].FragmentLength
;
978 if (Fragment
[CurrentFragment
].Len
== 0) {
981 Fragment
[CurrentFragment
].Bulk
+= RxData
.FragmentTable
[0].FragmentLength
;
987 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
988 TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
= NULL
;
990 TcpIo
->RxToken
.Tcp6Token
.Packet
.RxData
= NULL
;
993 if (Fragment
!= NULL
) {