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 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 EFI_OUT_OF_RESOURCES Failed to allocate memory.
127 @retval Others Failed to create the TCP socket or configure it.
134 IN EFI_HANDLE Controller
,
136 IN TCP_IO_CONFIG_DATA
*ConfigData
,
142 EFI_GUID
*ServiceBindingGuid
;
143 EFI_GUID
*ProtocolGuid
;
145 EFI_TCP4_OPTION ControlOption
;
146 EFI_TCP4_CONFIG_DATA Tcp4ConfigData
;
147 EFI_TCP4_ACCESS_POINT
*AccessPoint4
;
148 EFI_TCP4_PROTOCOL
*Tcp4
;
149 EFI_TCP6_CONFIG_DATA Tcp6ConfigData
;
150 EFI_TCP6_ACCESS_POINT
*AccessPoint6
;
151 EFI_TCP6_PROTOCOL
*Tcp6
;
152 EFI_TCP4_RECEIVE_DATA
*RxData
;
154 if ((Image
== NULL
) || (Controller
== NULL
) || (ConfigData
== NULL
) || (TcpIo
== NULL
)) {
155 return EFI_INVALID_PARAMETER
;
161 ZeroMem (TcpIo
, sizeof (TCP_IO
));
163 if (TcpVersion
== TCP_VERSION_4
) {
164 ServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
165 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
166 Interface
= (VOID
**) (&TcpIo
->Tcp
.Tcp4
);
167 } else if (TcpVersion
== TCP_VERSION_6
) {
168 ServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
169 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
170 Interface
= (VOID
**) (&TcpIo
->Tcp
.Tcp6
);
172 return EFI_UNSUPPORTED
;
175 TcpIo
->TcpVersion
= TcpVersion
;
178 // Create the TCP child instance and get the TCP protocol.
180 Status
= NetLibCreateServiceChild (
186 if (EFI_ERROR (Status
)) {
190 Status
= gBS
->OpenProtocol (
196 EFI_OPEN_PROTOCOL_BY_DRIVER
198 if (EFI_ERROR (Status
) || (*Interface
== NULL
)) {
202 if (TcpVersion
== TCP_VERSION_4
) {
203 Tcp4
= TcpIo
->Tcp
.Tcp4
;
205 Tcp6
= TcpIo
->Tcp
.Tcp6
;
208 TcpIo
->Image
= Image
;
209 TcpIo
->Controller
= Controller
;
212 // Set the configuration parameters.
214 ControlOption
.ReceiveBufferSize
= 0x200000;
215 ControlOption
.SendBufferSize
= 0x200000;
216 ControlOption
.MaxSynBackLog
= 0;
217 ControlOption
.ConnectionTimeout
= 0;
218 ControlOption
.DataRetries
= 6;
219 ControlOption
.FinTimeout
= 0;
220 ControlOption
.TimeWaitTimeout
= 0;
221 ControlOption
.KeepAliveProbes
= 4;
222 ControlOption
.KeepAliveTime
= 0;
223 ControlOption
.KeepAliveInterval
= 0;
224 ControlOption
.EnableNagle
= FALSE
;
225 ControlOption
.EnableTimeStamp
= FALSE
;
226 ControlOption
.EnableWindowScaling
= TRUE
;
227 ControlOption
.EnableSelectiveAck
= FALSE
;
228 ControlOption
.EnablePathMtuDiscovery
= FALSE
;
230 if (TcpVersion
== TCP_VERSION_4
) {
231 Tcp4ConfigData
.TypeOfService
= 8;
232 Tcp4ConfigData
.TimeToLive
= 255;
233 Tcp4ConfigData
.ControlOption
= &ControlOption
;
235 AccessPoint4
= &Tcp4ConfigData
.AccessPoint
;
237 ZeroMem (AccessPoint4
, sizeof (EFI_TCP4_ACCESS_POINT
));
238 AccessPoint4
->StationPort
= ConfigData
->Tcp4IoConfigData
.StationPort
;
239 AccessPoint4
->RemotePort
= ConfigData
->Tcp4IoConfigData
.RemotePort
;
240 AccessPoint4
->ActiveFlag
= ConfigData
->Tcp4IoConfigData
.ActiveFlag
;
243 &AccessPoint4
->StationAddress
,
244 &ConfigData
->Tcp4IoConfigData
.LocalIp
,
245 sizeof (EFI_IPv4_ADDRESS
)
248 &AccessPoint4
->SubnetMask
,
249 &ConfigData
->Tcp4IoConfigData
.SubnetMask
,
250 sizeof (EFI_IPv4_ADDRESS
)
253 &AccessPoint4
->RemoteAddress
,
254 &ConfigData
->Tcp4IoConfigData
.RemoteIp
,
255 sizeof (EFI_IPv4_ADDRESS
)
258 ASSERT (Tcp4
!= NULL
);
261 // Configure the TCP4 protocol.
263 Status
= Tcp4
->Configure (Tcp4
, &Tcp4ConfigData
);
264 if (EFI_ERROR (Status
)) {
268 if (!EFI_IP4_EQUAL (&ConfigData
->Tcp4IoConfigData
.Gateway
, &mZeroIp4Addr
)) {
270 // The gateway is not zero. Add the default route manually.
272 Status
= Tcp4
->Routes (
277 &ConfigData
->Tcp4IoConfigData
.Gateway
279 if (EFI_ERROR (Status
)) {
284 Tcp6ConfigData
.TrafficClass
= 0;
285 Tcp6ConfigData
.HopLimit
= 255;
286 Tcp6ConfigData
.ControlOption
= (EFI_TCP6_OPTION
*) &ControlOption
;
288 AccessPoint6
= &Tcp6ConfigData
.AccessPoint
;
290 ZeroMem (AccessPoint6
, sizeof (EFI_TCP6_ACCESS_POINT
));
291 AccessPoint6
->StationPort
= ConfigData
->Tcp6IoConfigData
.StationPort
;
292 AccessPoint6
->RemotePort
= ConfigData
->Tcp6IoConfigData
.RemotePort
;
293 AccessPoint6
->ActiveFlag
= ConfigData
->Tcp6IoConfigData
.ActiveFlag
;
295 IP6_COPY_ADDRESS (&AccessPoint6
->RemoteAddress
, &ConfigData
->Tcp6IoConfigData
.RemoteIp
);
298 ASSERT (Tcp6
!= NULL
);
300 // Configure the TCP6 protocol.
302 Status
= Tcp6
->Configure (Tcp6
, &Tcp6ConfigData
);
303 if (Status
== EFI_NO_MAPPING
) {
304 Status
= TcpIoGetMapping (Tcp6
, &Tcp6ConfigData
);
307 if (EFI_ERROR (Status
)) {
313 // Create events for variuos asynchronous operations.
315 Status
= gBS
->CreateEvent (
322 if (EFI_ERROR (Status
)) {
326 TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
328 Status
= gBS
->CreateEvent (
332 &TcpIo
->IsListenDone
,
335 if (EFI_ERROR (Status
)) {
339 TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
341 Status
= gBS
->CreateEvent (
348 if (EFI_ERROR (Status
)) {
352 TcpIo
->TxToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
355 Status
= gBS
->CreateEvent (
362 if (EFI_ERROR (Status
)) {
366 TcpIo
->RxToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
368 RxData
= (EFI_TCP4_RECEIVE_DATA
*) AllocateZeroPool (sizeof (EFI_TCP4_RECEIVE_DATA
));
369 if (RxData
== NULL
) {
370 Status
= EFI_OUT_OF_RESOURCES
;
374 TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
= RxData
;
376 Status
= gBS
->CreateEvent (
383 if (EFI_ERROR (Status
)) {
387 TcpIo
->CloseToken
.Tcp4Token
.CompletionToken
.Event
= Event
;
394 TcpIoDestroySocket (TcpIo
);
402 @param[in] TcpIo The TcpIo which wraps the socket to be destroyed.
412 EFI_TCP4_PROTOCOL
*Tcp4
;
413 EFI_TCP6_PROTOCOL
*Tcp6
;
415 EFI_GUID
*ServiceBindingGuid
;
416 EFI_GUID
*ProtocolGuid
;
417 EFI_HANDLE ChildHandle
;
423 TcpVersion
= TcpIo
->TcpVersion
;
425 if ((TcpVersion
!= TCP_VERSION_4
) && (TcpVersion
!= TCP_VERSION_6
)) {
429 Event
= TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
.Event
;
432 gBS
->CloseEvent (Event
);
435 Event
= TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
.Event
;
438 gBS
->CloseEvent (Event
);
441 Event
= TcpIo
->TxToken
.Tcp4Token
.CompletionToken
.Event
;
444 gBS
->CloseEvent (Event
);
447 Event
= TcpIo
->RxToken
.Tcp4Token
.CompletionToken
.Event
;
450 gBS
->CloseEvent (Event
);
453 Event
= TcpIo
->CloseToken
.Tcp4Token
.CompletionToken
.Event
;
456 gBS
->CloseEvent (Event
);
459 if (TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
!= NULL
) {
460 FreePool (TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
);
467 if (TcpVersion
== TCP_VERSION_4
) {
468 ServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
469 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
470 Tcp4
= TcpIo
->Tcp
.Tcp4
;
472 Tcp4
->Configure (Tcp4
, NULL
);
475 ServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
476 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
477 Tcp6
= TcpIo
->Tcp
.Tcp6
;
479 Tcp6
->Configure (Tcp6
, NULL
);
483 if ((Tcp4
!= NULL
) || (Tcp6
!= NULL
)) {
495 if (TcpIo
->IsListenDone
) {
496 if (TcpVersion
== TCP_VERSION_4
) {
497 Tcp4
= TcpIo
->NewTcp
.Tcp4
;
499 Tcp4
->Configure (Tcp4
, NULL
);
500 ChildHandle
= TcpIo
->ListenToken
.Tcp4Token
.NewChildHandle
;
503 Tcp6
= TcpIo
->NewTcp
.Tcp6
;
505 Tcp6
->Configure (Tcp6
, NULL
);
506 ChildHandle
= TcpIo
->ListenToken
.Tcp6Token
.NewChildHandle
;
510 if (ChildHandle
!= NULL
) {
521 NetLibDestroyServiceChild (
530 Connect to the other endpoint of the TCP socket.
532 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
533 @param[in] Timeout The time to wait for connection done. Set to NULL for infinite wait.
535 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket
537 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the
538 TCP socket in the specified time period.
539 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
540 @retval EFI_UNSUPPORTED One or more of the control options are not
541 supported in the implementation.
542 @retval Others Other errors as indicated.
548 IN OUT TCP_IO
*TcpIo
,
549 IN EFI_EVENT Timeout OPTIONAL
552 EFI_TCP4_PROTOCOL
*Tcp4
;
553 EFI_TCP6_PROTOCOL
*Tcp6
;
556 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)) {
557 return EFI_INVALID_PARAMETER
;
560 TcpIo
->IsConnDone
= FALSE
;
565 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
566 Tcp4
= TcpIo
->Tcp
.Tcp4
;
567 Status
= Tcp4
->Connect (Tcp4
, &TcpIo
->ConnToken
.Tcp4Token
);
568 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
569 Tcp6
= TcpIo
->Tcp
.Tcp6
;
570 Status
= Tcp6
->Connect (Tcp6
, &TcpIo
->ConnToken
.Tcp6Token
);
572 return EFI_UNSUPPORTED
;
575 if (EFI_ERROR (Status
)) {
579 while (!TcpIo
->IsConnDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
580 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
587 if (!TcpIo
->IsConnDone
) {
588 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
589 Tcp4
->Cancel (Tcp4
, &TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
);
591 Tcp6
->Cancel (Tcp6
, &TcpIo
->ConnToken
.Tcp6Token
.CompletionToken
);
593 Status
= EFI_TIMEOUT
;
595 Status
= TcpIo
->ConnToken
.Tcp4Token
.CompletionToken
.Status
;
602 Accept the incomding request from the other endpoint of the TCP socket.
604 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
605 @param[in] Timeout The time to wait for connection done. Set to NULL for infinite wait.
608 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket
610 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
611 @retval EFI_UNSUPPORTED One or more of the control options are not
612 supported in the implementation.
614 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the
615 TCP socket in the specified time period.
616 @retval Others Other errors as indicated.
622 IN OUT TCP_IO
*TcpIo
,
623 IN EFI_EVENT Timeout OPTIONAL
627 EFI_GUID
*ProtocolGuid
;
628 EFI_TCP4_PROTOCOL
*Tcp4
;
629 EFI_TCP6_PROTOCOL
*Tcp6
;
631 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)) {
632 return EFI_INVALID_PARAMETER
;
635 TcpIo
->IsListenDone
= FALSE
;
640 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
641 Tcp4
= TcpIo
->Tcp
.Tcp4
;
642 Status
= Tcp4
->Accept (Tcp4
, &TcpIo
->ListenToken
.Tcp4Token
);
643 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
644 Tcp6
= TcpIo
->Tcp
.Tcp6
;
645 Status
= Tcp6
->Accept (Tcp6
, &TcpIo
->ListenToken
.Tcp6Token
);
647 return EFI_UNSUPPORTED
;
650 if (EFI_ERROR (Status
)) {
654 while (!TcpIo
->IsListenDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
655 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
662 if (!TcpIo
->IsListenDone
) {
663 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
664 Tcp4
->Cancel (Tcp4
, &TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
);
666 Tcp6
->Cancel (Tcp6
, &TcpIo
->ListenToken
.Tcp6Token
.CompletionToken
);
668 Status
= EFI_TIMEOUT
;
670 Status
= TcpIo
->ListenToken
.Tcp4Token
.CompletionToken
.Status
;
674 // The new TCP instance handle created for the established connection is
677 if (!EFI_ERROR (Status
)) {
678 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
679 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
681 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
684 Status
= gBS
->OpenProtocol (
685 TcpIo
->ListenToken
.Tcp4Token
.NewChildHandle
,
687 (VOID
**) (&TcpIo
->NewTcp
.Tcp4
),
690 EFI_OPEN_PROTOCOL_BY_DRIVER
701 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
710 EFI_TCP4_PROTOCOL
*Tcp4
;
711 EFI_TCP6_PROTOCOL
*Tcp6
;
714 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)) {
718 TcpIo
->IsCloseDone
= FALSE
;
722 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
723 TcpIo
->CloseToken
.Tcp4Token
.AbortOnClose
= TRUE
;
724 Tcp4
= TcpIo
->Tcp
.Tcp4
;
725 Status
= Tcp4
->Close (Tcp4
, &TcpIo
->CloseToken
.Tcp4Token
);
726 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
727 TcpIo
->CloseToken
.Tcp6Token
.AbortOnClose
= TRUE
;
728 Tcp6
= TcpIo
->Tcp
.Tcp6
;
729 Status
= Tcp6
->Close (Tcp6
, &TcpIo
->CloseToken
.Tcp6Token
);
734 if (EFI_ERROR (Status
)) {
738 while (!TcpIo
->IsCloseDone
) {
739 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
749 Transmit the Packet to the other endpoint of the socket.
751 @param[in] TcpIo The TcpIo wrapping the TCP socket.
752 @param[in] Packet The packet to transmit.
754 @retval EFI_SUCCESS The packet is trasmitted.
755 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
756 @retval EFI_UNSUPPORTED One or more of the control options are not
757 supported in the implementation.
758 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
759 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
760 @retval Others Other errors as indicated.
772 EFI_TCP4_PROTOCOL
*Tcp4
;
773 EFI_TCP6_PROTOCOL
*Tcp6
;
776 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)|| (Packet
== NULL
)) {
777 return EFI_INVALID_PARAMETER
;
780 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
782 Size
= sizeof (EFI_TCP4_TRANSMIT_DATA
) +
783 (Packet
->BlockOpNum
- 1) * sizeof (EFI_TCP4_FRAGMENT_DATA
);
784 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
785 Size
= sizeof (EFI_TCP6_TRANSMIT_DATA
) +
786 (Packet
->BlockOpNum
- 1) * sizeof (EFI_TCP6_FRAGMENT_DATA
);
788 return EFI_UNSUPPORTED
;
791 Data
= AllocatePool (Size
);
793 return EFI_OUT_OF_RESOURCES
;
796 ((EFI_TCP4_TRANSMIT_DATA
*) Data
)->Push
= TRUE
;
797 ((EFI_TCP4_TRANSMIT_DATA
*) Data
)->Urgent
= FALSE
;
798 ((EFI_TCP4_TRANSMIT_DATA
*) Data
)->DataLength
= Packet
->TotalSize
;
801 // Build the fragment table.
803 ((EFI_TCP4_TRANSMIT_DATA
*) Data
)->FragmentCount
= Packet
->BlockOpNum
;
807 (NET_FRAGMENT
*) &((EFI_TCP4_TRANSMIT_DATA
*) Data
)->FragmentTable
[0],
808 &((EFI_TCP4_TRANSMIT_DATA
*) Data
)->FragmentCount
813 Status
= EFI_DEVICE_ERROR
;
816 // Trasnmit the packet.
818 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
819 TcpIo
->TxToken
.Tcp4Token
.Packet
.TxData
= (EFI_TCP4_TRANSMIT_DATA
*) Data
;
820 Tcp4
= TcpIo
->Tcp
.Tcp4
;
821 if (TcpIo
->IsListenDone
) {
822 Tcp4
= TcpIo
->NewTcp
.Tcp4
;
829 Status
= Tcp4
->Transmit (Tcp4
, &TcpIo
->TxToken
.Tcp4Token
);
831 TcpIo
->TxToken
.Tcp6Token
.Packet
.TxData
= (EFI_TCP6_TRANSMIT_DATA
*) Data
;
832 Tcp6
= TcpIo
->Tcp
.Tcp6
;
833 if (TcpIo
->IsListenDone
) {
834 Tcp6
= TcpIo
->NewTcp
.Tcp6
;
841 Status
= Tcp6
->Transmit (Tcp6
, &TcpIo
->TxToken
.Tcp6Token
);
844 if (EFI_ERROR (Status
)) {
848 while (!TcpIo
->IsTxDone
) {
849 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
856 TcpIo
->IsTxDone
= FALSE
;
857 Status
= TcpIo
->TxToken
.Tcp4Token
.CompletionToken
.Status
;
867 Receive data from the socket.
869 @param[in, out] TcpIo The TcpIo which wraps the socket to be destroyed.
870 @param[in] Packet The buffer to hold the data copy from the socket rx buffer.
871 @param[in] AsyncMode Is this receive asyncronous or not.
872 @param[in] Timeout The time to wait for receiving the amount of data the Packet
873 can hold. Set to NULL for infinite wait.
875 @retval EFI_SUCCESS The required amount of data is received from the socket.
876 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
877 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
878 @retval EFI_OUT_OF_RESOURCES Failed to allocate momery.
879 @retval EFI_TIMEOUT Failed to receive the required amount of data in the
880 specified time period.
881 @retval Others Other errors as indicated.
887 IN OUT TCP_IO
*TcpIo
,
889 IN BOOLEAN AsyncMode
,
890 IN EFI_EVENT Timeout OPTIONAL
893 EFI_TCP4_PROTOCOL
*Tcp4
;
894 EFI_TCP6_PROTOCOL
*Tcp6
;
895 EFI_TCP4_RECEIVE_DATA
*RxData
;
897 NET_FRAGMENT
*Fragment
;
898 UINT32 FragmentCount
;
899 UINT32 CurrentFragment
;
901 if ((TcpIo
== NULL
) || (TcpIo
->Tcp
.Tcp4
== NULL
)|| (Packet
== NULL
)) {
902 return EFI_INVALID_PARAMETER
;
905 RxData
= TcpIo
->RxToken
.Tcp4Token
.Packet
.RxData
;
906 if (RxData
== NULL
) {
907 return EFI_INVALID_PARAMETER
;
913 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
914 Tcp4
= TcpIo
->Tcp
.Tcp4
;
916 if (TcpIo
->IsListenDone
) {
917 Tcp4
= TcpIo
->NewTcp
.Tcp4
;
921 return EFI_DEVICE_ERROR
;
924 } else if (TcpIo
->TcpVersion
== TCP_VERSION_6
) {
925 Tcp6
= TcpIo
->Tcp
.Tcp6
;
927 if (TcpIo
->IsListenDone
) {
928 Tcp6
= TcpIo
->NewTcp
.Tcp6
;
932 return EFI_DEVICE_ERROR
;
936 return EFI_UNSUPPORTED
;
939 FragmentCount
= Packet
->BlockOpNum
;
940 Fragment
= AllocatePool (FragmentCount
* sizeof (NET_FRAGMENT
));
941 if (Fragment
== NULL
) {
942 Status
= EFI_OUT_OF_RESOURCES
;
946 // Build the fragment table.
948 NetbufBuildExt (Packet
, Fragment
, &FragmentCount
);
950 RxData
->FragmentCount
= 1;
952 Status
= EFI_SUCCESS
;
954 while (CurrentFragment
< FragmentCount
) {
955 RxData
->DataLength
= Fragment
[CurrentFragment
].Len
;
956 RxData
->FragmentTable
[0].FragmentLength
= Fragment
[CurrentFragment
].Len
;
957 RxData
->FragmentTable
[0].FragmentBuffer
= Fragment
[CurrentFragment
].Bulk
;
959 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
960 Status
= Tcp4
->Receive (Tcp4
, &TcpIo
->RxToken
.Tcp4Token
);
962 Status
= Tcp6
->Receive (Tcp6
, &TcpIo
->RxToken
.Tcp6Token
);
965 if (EFI_ERROR (Status
)) {
969 while (!TcpIo
->IsRxDone
&& ((Timeout
== NULL
) || EFI_ERROR (gBS
->CheckEvent (Timeout
)))) {
971 // Poll until some data is received or an error occurs.
973 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
980 if (!TcpIo
->IsRxDone
) {
982 // Timeout occurs, cancel the receive request.
984 if (TcpIo
->TcpVersion
== TCP_VERSION_4
) {
985 Tcp4
->Cancel (Tcp4
, &TcpIo
->RxToken
.Tcp4Token
.CompletionToken
);
987 Tcp6
->Cancel (Tcp6
, &TcpIo
->RxToken
.Tcp6Token
.CompletionToken
);
990 Status
= EFI_TIMEOUT
;
993 TcpIo
->IsRxDone
= FALSE
;
996 Status
= TcpIo
->RxToken
.Tcp4Token
.CompletionToken
.Status
;
998 if (EFI_ERROR (Status
)) {
1002 Fragment
[CurrentFragment
].Len
-= RxData
->FragmentTable
[0].FragmentLength
;
1003 if (Fragment
[CurrentFragment
].Len
== 0) {
1006 Fragment
[CurrentFragment
].Bulk
+= RxData
->FragmentTable
[0].FragmentLength
;
1012 if (Fragment
!= NULL
) {
1013 FreePool (Fragment
);