From 4bad9adabc25c7d011a4da90a77f985d19c441e2 Mon Sep 17 00:00:00 2001 From: tye1 Date: Tue, 14 Dec 2010 03:19:21 +0000 Subject: [PATCH] Add a TcpIo library to facilitate usage of TCP service. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11162 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Include/Library/TcpIoLib.h | 252 +++++ .../Library/DxeTcpIoLib/DxeTcpIoLib.c | 993 ++++++++++++++++++ .../Library/DxeTcpIoLib/DxeTcpIoLib.inf | 53 + MdeModulePkg/MdeModulePkg.dec | 4 + MdeModulePkg/MdeModulePkg.dsc | 1 + 5 files changed, 1303 insertions(+) create mode 100644 MdeModulePkg/Include/Library/TcpIoLib.h create mode 100644 MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c create mode 100644 MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf diff --git a/MdeModulePkg/Include/Library/TcpIoLib.h b/MdeModulePkg/Include/Library/TcpIoLib.h new file mode 100644 index 0000000000..050f14b28f --- /dev/null +++ b/MdeModulePkg/Include/Library/TcpIoLib.h @@ -0,0 +1,252 @@ +/** @file + This library is used to share code between UEFI network stack modules. + It provides the helper routines to access TCP service. + +Copyright (c) 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _TCP_IO_H_ +#define _TCP_IO_H_ + + +#include +#include + +#include + +#define TCP_VERSION_4 IP_VERSION_4 +#define TCP_VERSION_6 IP_VERSION_6 + +/// +/// 10 seconds +/// +#define TCP_GET_MAPPING_TIMEOUT 100000000U + + +typedef struct { + EFI_IPv4_ADDRESS LocalIp; + EFI_IPv4_ADDRESS SubnetMask; + EFI_IPv4_ADDRESS Gateway; + + UINT16 StationPort; + EFI_IPv4_ADDRESS RemoteIp; + UINT16 RemotePort; + BOOLEAN ActiveFlag; +} TCP4_IO_CONFIG_DATA; + +typedef struct { + UINT16 StationPort; + EFI_IPv6_ADDRESS RemoteIp; + UINT16 RemotePort; + BOOLEAN ActiveFlag; +} TCP6_IO_CONFIG_DATA; + +typedef union { + TCP4_IO_CONFIG_DATA Tcp4IoConfigData; + TCP6_IO_CONFIG_DATA Tcp6IoConfigData; +} TCP_IO_CONFIG_DATA; + +typedef union { + EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP6_PROTOCOL *Tcp6; +} TCP_IO_PROTOCOL; + +typedef union { + EFI_TCP4_CONNECTION_TOKEN Tcp4Token; + EFI_TCP6_CONNECTION_TOKEN Tcp6Token; +} TCP_IO_CONNECTION_TOKEN; + +typedef union { + EFI_TCP4_IO_TOKEN Tcp4Token; + EFI_TCP6_IO_TOKEN Tcp6Token; +} TCP_IO_IO_TOKEN; + +typedef union { + EFI_TCP4_CLOSE_TOKEN Tcp4Token; + EFI_TCP6_CLOSE_TOKEN Tcp6Token; +} TCP_IO_CLOSE_TOKEN; + +typedef union { + EFI_TCP4_LISTEN_TOKEN Tcp4Token; + EFI_TCP6_LISTEN_TOKEN Tcp6Token; +} TCP_IO_LISTEN_TOKEN; + + +typedef struct { + UINT8 TcpVersion; + EFI_HANDLE Image; + EFI_HANDLE Controller; + EFI_HANDLE Handle; + + TCP_IO_PROTOCOL Tcp; + TCP_IO_PROTOCOL NewTcp; + TCP_IO_CONNECTION_TOKEN ConnToken; + TCP_IO_IO_TOKEN TxToken; + TCP_IO_IO_TOKEN RxToken; + TCP_IO_CLOSE_TOKEN CloseToken; + TCP_IO_LISTEN_TOKEN ListenToken; + + BOOLEAN IsConnDone; + BOOLEAN IsTxDone; + BOOLEAN IsRxDone; + BOOLEAN IsCloseDone; + BOOLEAN IsListenDone; +} TCP_IO; + +/** + Create a TCP socket with the specified configuration data. + + @param[in] Image The handle of the driver image. + @param[in] Controller The handle of the controller. + @param[in] TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6. + @param[in] ConfigData The Tcp configuration data. + @param[out] TcpIo The TcpIo. + + @retval EFI_SUCCESS The TCP socket is created and configured. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED One or more of the control options are not + supported in the implementation. + @retval Others Failed to create the TCP socket or configure it. + +**/ +EFI_STATUS +EFIAPI +TcpIoCreateSocket ( + IN EFI_HANDLE Image, + IN EFI_HANDLE Controller, + IN UINT8 TcpVersion, + IN TCP_IO_CONFIG_DATA *ConfigData, + OUT TCP_IO *TcpIo + ); + +/** + Destroy the socket. + + @param[in] TcpIo The TcpIo which wraps the socket to be destroyed. + +**/ +VOID +EFIAPI +TcpIoDestroySocket ( + IN TCP_IO *TcpIo + ); + +/** + Connect to the other endpoint of the TCP socket. + + @param[in, out] TcpIo The TcpIo wrapping the TCP socket. + @param[in] Timeout The time to wait for connection done. + + @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket + successfully. + @retval EFI_TIMEOUT Failed to connect to the other endpoint of the + TCP socket in the specified time period. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED One or more of the control options are not + supported in the implementation. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +EFIAPI +TcpIoConnect ( + IN OUT TCP_IO *TcpIo, + IN EFI_EVENT Timeout + ); + +/** + Accept the incomding request from the other endpoint of the TCP socket. + + @param[in, out] TcpIo The TcpIo wrapping the TCP socket. + @param[in] Timeout The time to wait for connection done. + + + @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket + successfully. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED One or more of the control options are not + supported in the implementation. + + @retval EFI_TIMEOUT Failed to connect to the other endpoint of the + TCP socket in the specified time period. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +EFIAPI +TcpIoAccept ( + IN OUT TCP_IO *TcpIo, + IN EFI_EVENT Timeout + ); + +/** + Reset the socket. + + @param[in, out] TcpIo The TcpIo wrapping the TCP socket. + +**/ +VOID +EFIAPI +TcpIoReset ( + IN OUT TCP_IO *TcpIo + ); + +/** + Transmit the Packet to the other endpoint of the socket. + + @param[in] TcpIo The TcpIo wrapping the TCP socket. + @param[in] Packet The packet to transmit. + + @retval EFI_SUCCESS The packet is trasmitted. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED One or more of the control options are not + supported in the implementation. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +EFIAPI +TcpIoTransmit ( + IN TCP_IO *TcpIo, + IN NET_BUF *Packet + ); + +/** + Receive data from the socket. + + @param[in, out] TcpIo The TcpIo which wraps the socket to be destroyed. + @param[in] Packet The buffer to hold the data copy from the socket rx buffer. + @param[in] AsyncMode Is this receive asyncronous or not. + @param[in] Timeout The time to wait for receiving the amount of data the Packet + can hold. + + @retval EFI_SUCCESS The required amount of data is received from the socket. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval EFI_OUT_OF_RESOURCES Failed to allocate momery. + @retval EFI_TIMEOUT Failed to receive the required amount of data in the + specified time period. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +EFIAPI +TcpIoReceive ( + IN OUT TCP_IO *TcpIo, + IN NET_BUF *Packet, + IN BOOLEAN AsyncMode, + IN EFI_EVENT Timeout + ); + +#endif + diff --git a/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c b/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c new file mode 100644 index 0000000000..48120b4353 --- /dev/null +++ b/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c @@ -0,0 +1,993 @@ +/** @file + This library is used to share code between UEFI network stack modules. + It provides the helper routines to access TCP service. + +Copyright (c) 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include + +/** + The common notify function associated with various TcpIo events. + + @param[in] Event The event signaled. + @param[in] Context The context. + +**/ +VOID +EFIAPI +TcpIoCommonNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + if ((Event == NULL) || (Context == NULL)) { + return ; + } + + *((BOOLEAN *) Context) = TRUE; +} + +/** + The internal function for delay configuring TCP6 when IP6 driver is still in DAD. + + @param[in] Tcp6 The EFI_TCP6_PROTOCOL protocol instance. + @param[in] Tcp6ConfigData The Tcp6 configuration data. + + @retval EFI_SUCCESS The operational settings successfully + completed. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval Others Failed to finish the operation. + +**/ +EFI_STATUS +TcpIoGetMapping ( + IN EFI_TCP6_PROTOCOL *Tcp6, + IN EFI_TCP6_CONFIG_DATA *Tcp6ConfigData + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + if ((Tcp6 == NULL) || (Tcp6ConfigData == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Event = NULL; + Status = gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &Event + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = gBS->SetTimer ( + Event, + TimerRelative, + TCP_GET_MAPPING_TIMEOUT + ); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + while (EFI_ERROR (gBS->CheckEvent (Event))) { + + Tcp6->Poll (Tcp6); + + Status = Tcp6->Configure (Tcp6, Tcp6ConfigData); + + if (!EFI_ERROR (Status)) { + break; + } + } + +ON_EXIT: + + if (Event != NULL) { + gBS->CloseEvent (Event); + } + + return Status; +} + +/** + Create a TCP socket with the specified configuration data. + + @param[in] Image The handle of the driver image. + @param[in] Controller The handle of the controller. + @param[in] TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6. + @param[in] ConfigData The Tcp configuration data. + @param[out] TcpIo The TcpIo. + + @retval EFI_SUCCESS The TCP socket is created and configured. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED One or more of the control options are not + supported in the implementation. + @retval Others Failed to create the TCP socket or configure it. + +**/ +EFI_STATUS +EFIAPI +TcpIoCreateSocket ( + IN EFI_HANDLE Image, + IN EFI_HANDLE Controller, + IN UINT8 TcpVersion, + IN TCP_IO_CONFIG_DATA *ConfigData, + OUT TCP_IO *TcpIo + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + EFI_GUID *ServiceBindingGuid; + EFI_GUID *ProtocolGuid; + VOID **Interface; + EFI_TCP4_OPTION ControlOption; + EFI_TCP4_CONFIG_DATA Tcp4ConfigData; + EFI_TCP4_ACCESS_POINT *AccessPoint4; + EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP6_CONFIG_DATA Tcp6ConfigData; + EFI_TCP6_ACCESS_POINT *AccessPoint6; + EFI_TCP6_PROTOCOL *Tcp6; + + if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (TcpIo == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Tcp4 = NULL; + Tcp6 = NULL; + + ZeroMem (TcpIo, sizeof (TCP_IO)); + + if (TcpVersion == TCP_VERSION_4) { + ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid; + ProtocolGuid = &gEfiTcp4ProtocolGuid; + Interface = (VOID **) (&TcpIo->Tcp.Tcp4); + } else if (TcpVersion == TCP_VERSION_6) { + ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid; + ProtocolGuid = &gEfiTcp6ProtocolGuid; + Interface = (VOID **) (&TcpIo->Tcp.Tcp6); + } else { + return EFI_UNSUPPORTED; + } + + TcpIo->TcpVersion = TcpVersion; + + // + // Create the TCP child instance and get the TCP protocol. + // + Status = NetLibCreateServiceChild ( + Controller, + Image, + ServiceBindingGuid, + &TcpIo->Handle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + TcpIo->Handle, + ProtocolGuid, + Interface, + Image, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) || (*Interface == NULL)) { + goto ON_ERROR; + } + + if (TcpVersion == TCP_VERSION_4) { + Tcp4 = TcpIo->Tcp.Tcp4; + } else { + Tcp6 = TcpIo->Tcp.Tcp6; + } + + TcpIo->Image = Image; + TcpIo->Controller = Controller; + + // + // Set the configuration parameters. + // + ControlOption.ReceiveBufferSize = 0x200000; + ControlOption.SendBufferSize = 0x200000; + ControlOption.MaxSynBackLog = 0; + ControlOption.ConnectionTimeout = 0; + ControlOption.DataRetries = 6; + ControlOption.FinTimeout = 0; + ControlOption.TimeWaitTimeout = 0; + ControlOption.KeepAliveProbes = 4; + ControlOption.KeepAliveTime = 0; + ControlOption.KeepAliveInterval = 0; + ControlOption.EnableNagle = FALSE; + ControlOption.EnableTimeStamp = FALSE; + ControlOption.EnableWindowScaling = TRUE; + ControlOption.EnableSelectiveAck = FALSE; + ControlOption.EnablePathMtuDiscovery = FALSE; + + if (TcpVersion == TCP_VERSION_4) { + Tcp4ConfigData.TypeOfService = 8; + Tcp4ConfigData.TimeToLive = 255; + Tcp4ConfigData.ControlOption = &ControlOption; + + AccessPoint4 = &Tcp4ConfigData.AccessPoint; + + ZeroMem (AccessPoint4, sizeof (EFI_TCP4_ACCESS_POINT)); + AccessPoint4->StationPort = ConfigData->Tcp4IoConfigData.StationPort; + AccessPoint4->RemotePort = ConfigData->Tcp4IoConfigData.RemotePort; + AccessPoint4->ActiveFlag = ConfigData->Tcp4IoConfigData.ActiveFlag; + + CopyMem ( + &AccessPoint4->StationAddress, + &ConfigData->Tcp4IoConfigData.LocalIp, + sizeof (EFI_IPv4_ADDRESS) + ); + CopyMem ( + &AccessPoint4->SubnetMask, + &ConfigData->Tcp4IoConfigData.SubnetMask, + sizeof (EFI_IPv4_ADDRESS) + ); + CopyMem ( + &AccessPoint4->RemoteAddress, + &ConfigData->Tcp4IoConfigData.RemoteIp, + sizeof (EFI_IPv4_ADDRESS) + ); + + ASSERT (Tcp4 != NULL); + + // + // Configure the TCP4 protocol. + // + Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + if (!EFI_IP4_EQUAL (&ConfigData->Tcp4IoConfigData.Gateway, &mZeroIp4Addr)) { + // + // The gateway is not zero. Add the default route manually. + // + Status = Tcp4->Routes ( + Tcp4, + FALSE, + &mZeroIp4Addr, + &mZeroIp4Addr, + &ConfigData->Tcp4IoConfigData.Gateway + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + } + } else { + Tcp6ConfigData.TrafficClass = 0; + Tcp6ConfigData.HopLimit = 255; + Tcp6ConfigData.ControlOption = (EFI_TCP6_OPTION *) &ControlOption; + + AccessPoint6 = &Tcp6ConfigData.AccessPoint; + + ZeroMem (AccessPoint6, sizeof (EFI_TCP6_ACCESS_POINT)); + AccessPoint6->StationPort = ConfigData->Tcp6IoConfigData.StationPort; + AccessPoint6->RemotePort = ConfigData->Tcp6IoConfigData.RemotePort; + AccessPoint6->ActiveFlag = ConfigData->Tcp6IoConfigData.ActiveFlag; + + IP6_COPY_ADDRESS (&AccessPoint6->RemoteAddress, &ConfigData->Tcp6IoConfigData.RemoteIp); + + + ASSERT (Tcp6 != NULL); + // + // Configure the TCP6 protocol. + // + Status = Tcp6->Configure (Tcp6, &Tcp6ConfigData); + if (Status == EFI_NO_MAPPING) { + Status = TcpIoGetMapping (Tcp6, &Tcp6ConfigData); + } + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + } + + // + // Create events for variuos asynchronous operations. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + TcpIoCommonNotify, + &TcpIo->IsConnDone, + &Event + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + TcpIo->ConnToken.Tcp4Token.CompletionToken.Event = Event; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + TcpIoCommonNotify, + &TcpIo->IsListenDone, + &Event + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + TcpIo->ListenToken.Tcp4Token.CompletionToken.Event = Event; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + TcpIoCommonNotify, + &TcpIo->IsTxDone, + &Event + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + TcpIo->TxToken.Tcp4Token.CompletionToken.Event = Event; + + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + TcpIoCommonNotify, + &TcpIo->IsRxDone, + &Event + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + TcpIo->RxToken.Tcp4Token.CompletionToken.Event = Event; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + TcpIoCommonNotify, + &TcpIo->IsCloseDone, + &Event + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + TcpIo->CloseToken.Tcp4Token.CompletionToken.Event = Event; + + + return EFI_SUCCESS; + +ON_ERROR: + + TcpIoDestroySocket (TcpIo); + + return Status; +} + +/** + Destroy the socket. + + @param[in] TcpIo The TcpIo which wraps the socket to be destroyed. + +**/ +VOID +EFIAPI +TcpIoDestroySocket ( + IN TCP_IO *TcpIo + ) +{ + EFI_EVENT Event; + EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP6_PROTOCOL *Tcp6; + UINT8 TcpVersion; + EFI_GUID *ServiceBindingGuid; + EFI_GUID *ProtocolGuid; + EFI_HANDLE ChildHandle; + + if (TcpIo == NULL) { + return ; + } + + TcpVersion = TcpIo->TcpVersion; + + if ((TcpVersion != TCP_VERSION_4) && (TcpVersion != TCP_VERSION_6)) { + return ; + } + + Event = TcpIo->ConnToken.Tcp4Token.CompletionToken.Event; + + if (Event != NULL) { + gBS->CloseEvent (Event); + } + + Event = TcpIo->ListenToken.Tcp4Token.CompletionToken.Event; + + if (Event != NULL) { + gBS->CloseEvent (Event); + } + + Event = TcpIo->TxToken.Tcp4Token.CompletionToken.Event; + + if (Event != NULL) { + gBS->CloseEvent (Event); + } + + Event = TcpIo->RxToken.Tcp4Token.CompletionToken.Event; + + if (Event != NULL) { + gBS->CloseEvent (Event); + } + + Event = TcpIo->CloseToken.Tcp4Token.CompletionToken.Event; + + if (Event != NULL) { + gBS->CloseEvent (Event); + } + + Tcp4 = NULL; + Tcp6 = NULL; + + + if (TcpVersion == TCP_VERSION_4) { + ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid; + ProtocolGuid = &gEfiTcp4ProtocolGuid; + Tcp4 = TcpIo->Tcp.Tcp4; + if (Tcp4 != NULL) { + Tcp4->Configure (Tcp4, NULL); + } + } else { + ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid; + ProtocolGuid = &gEfiTcp6ProtocolGuid; + Tcp6 = TcpIo->Tcp.Tcp6; + if (Tcp6 != NULL) { + Tcp6->Configure (Tcp6, NULL); + } + } + + if ((Tcp4 != NULL) || (Tcp6 != NULL)) { + + gBS->CloseProtocol ( + TcpIo->Handle, + ProtocolGuid, + TcpIo->Image, + TcpIo->Controller + ); + } + + ChildHandle = NULL; + + if (TcpIo->IsListenDone) { + if (TcpVersion == TCP_VERSION_4) { + Tcp4 = TcpIo->NewTcp.Tcp4; + if (Tcp4 != NULL) { + Tcp4->Configure (Tcp4, NULL); + ChildHandle = TcpIo->ListenToken.Tcp4Token.NewChildHandle; + } + } else { + Tcp6 = TcpIo->NewTcp.Tcp6; + if (Tcp6 != NULL) { + Tcp6->Configure (Tcp6, NULL); + ChildHandle = TcpIo->ListenToken.Tcp6Token.NewChildHandle; + } + } + + if (ChildHandle != NULL) { + + gBS->CloseProtocol ( + ChildHandle, + ProtocolGuid, + TcpIo->Image, + TcpIo->Controller + ); + } + } + + NetLibDestroyServiceChild ( + TcpIo->Controller, + TcpIo->Image, + ServiceBindingGuid, + TcpIo->Handle + ); +} + +/** + Connect to the other endpoint of the TCP socket. + + @param[in, out] TcpIo The TcpIo wrapping the TCP socket. + @param[in] Timeout The time to wait for connection done. + + @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket + successfully. + @retval EFI_TIMEOUT Failed to connect to the other endpoint of the + TCP socket in the specified time period. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED One or more of the control options are not + supported in the implementation. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +EFIAPI +TcpIoConnect ( + IN OUT TCP_IO *TcpIo, + IN EFI_EVENT Timeout + ) +{ + EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP6_PROTOCOL *Tcp6; + EFI_STATUS Status; + + if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) { + return EFI_INVALID_PARAMETER; + } + + TcpIo->IsConnDone = FALSE; + + Tcp4 = NULL; + Tcp6 = NULL; + + if (TcpIo->TcpVersion == TCP_VERSION_4) { + Tcp4 = TcpIo->Tcp.Tcp4; + Status = Tcp4->Connect (Tcp4, &TcpIo->ConnToken.Tcp4Token); + } else if (TcpIo->TcpVersion == TCP_VERSION_6) { + Tcp6 = TcpIo->Tcp.Tcp6; + Status = Tcp6->Connect (Tcp6, &TcpIo->ConnToken.Tcp6Token); + } else { + return EFI_UNSUPPORTED; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + while (!TcpIo->IsConnDone && EFI_ERROR (gBS->CheckEvent (Timeout))) { + if (TcpIo->TcpVersion == TCP_VERSION_4) { + Tcp4->Poll (Tcp4); + } else { + Tcp6->Poll (Tcp6); + } + } + + if (!TcpIo->IsConnDone) { + Status = EFI_TIMEOUT; + } else { + Status = TcpIo->ConnToken.Tcp4Token.CompletionToken.Status; + } + + return Status; +} + +/** + Accept the incomding request from the other endpoint of the TCP socket. + + @param[in, out] TcpIo The TcpIo wrapping the TCP socket. + @param[in] Timeout The time to wait for connection done. + + + @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket + successfully. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED One or more of the control options are not + supported in the implementation. + + @retval EFI_TIMEOUT Failed to connect to the other endpoint of the + TCP socket in the specified time period. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +EFIAPI +TcpIoAccept ( + IN OUT TCP_IO *TcpIo, + IN EFI_EVENT Timeout + ) +{ + EFI_STATUS Status; + EFI_GUID *ProtocolGuid; + EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP6_PROTOCOL *Tcp6; + + if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) { + return EFI_INVALID_PARAMETER; + } + + TcpIo->IsListenDone = FALSE; + + Tcp4 = NULL; + Tcp6 = NULL; + + if (TcpIo->TcpVersion == TCP_VERSION_4) { + Tcp4 = TcpIo->Tcp.Tcp4; + Status = Tcp4->Accept (Tcp4, &TcpIo->ListenToken.Tcp4Token); + } else if (TcpIo->TcpVersion == TCP_VERSION_6) { + Tcp6 = TcpIo->Tcp.Tcp6; + Status = Tcp6->Accept (Tcp6, &TcpIo->ListenToken.Tcp6Token); + } else { + return EFI_UNSUPPORTED; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + while (!TcpIo->IsListenDone && EFI_ERROR (gBS->CheckEvent (Timeout))) { + if (TcpIo->TcpVersion == TCP_VERSION_4) { + Tcp4->Poll (Tcp4); + } else { + Tcp6->Poll (Tcp6); + } + } + + if (!TcpIo->IsListenDone) { + Status = EFI_TIMEOUT; + } else { + Status = TcpIo->ListenToken.Tcp4Token.CompletionToken.Status; + } + + // + // The new TCP instance handle created for the established connection is + // in ListenToken. + // + if (!EFI_ERROR (Status)) { + if (TcpIo->TcpVersion == TCP_VERSION_4) { + ProtocolGuid = &gEfiTcp4ProtocolGuid; + } else { + ProtocolGuid = &gEfiTcp6ProtocolGuid; + } + + Status = gBS->OpenProtocol ( + TcpIo->ListenToken.Tcp4Token.NewChildHandle, + ProtocolGuid, + (VOID **) (&TcpIo->NewTcp.Tcp4), + TcpIo->Image, + TcpIo->Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + } + + return Status; +} + +/** + Reset the socket. + + @param[in, out] TcpIo The TcpIo wrapping the TCP socket. + +**/ +VOID +EFIAPI +TcpIoReset ( + IN OUT TCP_IO *TcpIo + ) +{ + EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP6_PROTOCOL *Tcp6; + EFI_STATUS Status; + + if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) { + return ; + } + + TcpIo->IsCloseDone = FALSE; + Tcp4 = NULL; + Tcp6 = NULL; + + if (TcpIo->TcpVersion == TCP_VERSION_4) { + TcpIo->CloseToken.Tcp4Token.AbortOnClose = TRUE; + Tcp4 = TcpIo->Tcp.Tcp4; + Status = Tcp4->Close (Tcp4, &TcpIo->CloseToken.Tcp4Token); + } else if (TcpIo->TcpVersion == TCP_VERSION_6) { + TcpIo->CloseToken.Tcp6Token.AbortOnClose = TRUE; + Tcp6 = TcpIo->Tcp.Tcp6; + Status = Tcp6->Close (Tcp6, &TcpIo->CloseToken.Tcp6Token); + } else { + return ; + } + + if (EFI_ERROR (Status)) { + return ; + } + + while (!TcpIo->IsCloseDone) { + if (TcpIo->TcpVersion == TCP_VERSION_4) { + Tcp4->Poll (Tcp4); + } else { + Tcp6->Poll (Tcp6); + } + } +} + + +/** + Transmit the Packet to the other endpoint of the socket. + + @param[in] TcpIo The TcpIo wrapping the TCP socket. + @param[in] Packet The packet to transmit. + + @retval EFI_SUCCESS The packet is trasmitted. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED One or more of the control options are not + supported in the implementation. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +EFIAPI +TcpIoTransmit ( + IN TCP_IO *TcpIo, + IN NET_BUF *Packet + ) +{ + EFI_STATUS Status; + VOID *Data; + EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP6_PROTOCOL *Tcp6; + UINTN Size; + + if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (TcpIo->TcpVersion == TCP_VERSION_4) { + + Size = sizeof (EFI_TCP4_TRANSMIT_DATA) + + (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA); + } else if (TcpIo->TcpVersion == TCP_VERSION_6) { + Size = sizeof (EFI_TCP6_TRANSMIT_DATA) + + (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA); + } else { + return EFI_UNSUPPORTED; + } + + Data = AllocatePool (Size); + if (Data == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push = TRUE; + ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent = FALSE; + ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize; + + // + // Build the fragment table. + // + ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum; + + NetbufBuildExt ( + Packet, + (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0], + &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount + ); + + Tcp4 = NULL; + Tcp6 = NULL; + Status = EFI_DEVICE_ERROR; + + // + // Trasnmit the packet. + // + if (TcpIo->TcpVersion == TCP_VERSION_4) { + TcpIo->TxToken.Tcp4Token.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data; + Tcp4 = TcpIo->Tcp.Tcp4; + if (TcpIo->IsListenDone) { + Tcp4 = TcpIo->NewTcp.Tcp4; + } + + if (Tcp4 == NULL) { + goto ON_EXIT; + } + + Status = Tcp4->Transmit (Tcp4, &TcpIo->TxToken.Tcp4Token); + } else { + TcpIo->TxToken.Tcp6Token.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data; + Tcp6 = TcpIo->Tcp.Tcp6; + if (TcpIo->IsListenDone) { + Tcp6 = TcpIo->NewTcp.Tcp6; + } + + if (Tcp6 == NULL) { + goto ON_EXIT; + } + + Status = Tcp6->Transmit (Tcp6, &TcpIo->TxToken.Tcp6Token); + } + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + while (!TcpIo->IsTxDone) { + if (TcpIo->TcpVersion == TCP_VERSION_4) { + Tcp4->Poll (Tcp4); + } else { + Tcp6->Poll (Tcp6); + } + } + + TcpIo->IsTxDone = FALSE; + Status = TcpIo->TxToken.Tcp4Token.CompletionToken.Status; + +ON_EXIT: + + FreePool (Data); + + return Status; +} + +/** + Receive data from the socket. + + @param[in, out] TcpIo The TcpIo which wraps the socket to be destroyed. + @param[in] Packet The buffer to hold the data copy from the socket rx buffer. + @param[in] AsyncMode Is this receive asyncronous or not. + @param[in] Timeout The time to wait for receiving the amount of data the Packet + can hold. + + @retval EFI_SUCCESS The required amount of data is received from the socket. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval EFI_OUT_OF_RESOURCES Failed to allocate momery. + @retval EFI_TIMEOUT Failed to receive the required amount of data in the + specified time period. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +EFIAPI +TcpIoReceive ( + IN OUT TCP_IO *TcpIo, + IN NET_BUF *Packet, + IN BOOLEAN AsyncMode, + IN EFI_EVENT Timeout + ) +{ + EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP6_PROTOCOL *Tcp6; + EFI_TCP4_RECEIVE_DATA RxData; + EFI_STATUS Status; + NET_FRAGMENT *Fragment; + UINT32 FragmentCount; + UINT32 CurrentFragment; + + if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Tcp4 = NULL; + Tcp6 = NULL; + + if (TcpIo->TcpVersion == TCP_VERSION_4) { + TcpIo->RxToken.Tcp4Token.Packet.RxData = &RxData; + Tcp4 = TcpIo->Tcp.Tcp4; + + if (TcpIo->IsListenDone) { + Tcp4 = TcpIo->NewTcp.Tcp4; + } + + if (Tcp4 == NULL) { + return EFI_DEVICE_ERROR; + } + + } else if (TcpIo->TcpVersion == TCP_VERSION_6) { + TcpIo->RxToken.Tcp6Token.Packet.RxData = (EFI_TCP6_RECEIVE_DATA *) &RxData; + Tcp6 = TcpIo->Tcp.Tcp6; + + if (TcpIo->IsListenDone) { + Tcp6 = TcpIo->NewTcp.Tcp6; + } + + if (Tcp6 == NULL) { + return EFI_DEVICE_ERROR; + } + + } else { + return EFI_UNSUPPORTED; + } + + FragmentCount = Packet->BlockOpNum; + Fragment = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT)); + if (Fragment == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Build the fragment table. + // + NetbufBuildExt (Packet, Fragment, &FragmentCount); + + RxData.FragmentCount = 1; + CurrentFragment = 0; + Status = EFI_SUCCESS; + + while (CurrentFragment < FragmentCount) { + RxData.DataLength = Fragment[CurrentFragment].Len; + RxData.FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len; + RxData.FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk; + + if (TcpIo->TcpVersion == TCP_VERSION_4) { + Status = Tcp4->Receive (Tcp4, &TcpIo->RxToken.Tcp4Token); + } else { + Status = Tcp6->Receive (Tcp6, &TcpIo->RxToken.Tcp6Token); + } + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + while (!TcpIo->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) { + // + // Poll until some data is received or an error occurs. + // + if (TcpIo->TcpVersion == TCP_VERSION_4) { + Tcp4->Poll (Tcp4); + } else { + Tcp6->Poll (Tcp6); + } + } + + if (!TcpIo->IsRxDone) { + // + // Timeout occurs, cancel the receive request. + // + if (TcpIo->TcpVersion == TCP_VERSION_4) { + Tcp4->Cancel (Tcp4, &TcpIo->RxToken.Tcp4Token.CompletionToken); + } else { + Tcp6->Cancel (Tcp6, &TcpIo->RxToken.Tcp6Token.CompletionToken); + } + + Status = EFI_TIMEOUT; + goto ON_EXIT; + } else { + TcpIo->IsRxDone = FALSE; + } + + Status = TcpIo->RxToken.Tcp4Token.CompletionToken.Status; + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Fragment[CurrentFragment].Len -= RxData.FragmentTable[0].FragmentLength; + if (Fragment[CurrentFragment].Len == 0) { + CurrentFragment++; + } else { + Fragment[CurrentFragment].Bulk += RxData.FragmentTable[0].FragmentLength; + } + } + +ON_EXIT: + + if (TcpIo->TcpVersion == TCP_VERSION_4) { + TcpIo->RxToken.Tcp4Token.Packet.RxData = NULL; + } else { + TcpIo->RxToken.Tcp6Token.Packet.RxData = NULL; + } + + FreePool (Fragment); + + return Status; +} diff --git a/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf b/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf new file mode 100644 index 0000000000..808b98bed5 --- /dev/null +++ b/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf @@ -0,0 +1,53 @@ +## @file +# Instance of TcpIoLib. +# +# This module provides TCP services by consuming EFI TCP Service Binding Protocol and +# EFI TCP Protocol. +# +# Copyright (c) 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeTcpIoLib + FILE_GUID = D4608509-1AB0-4cc7-827A-AB8E1E7BD3E6 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = TcpIoLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + DxeTcpIoLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + + +[LibraryClasses] + TcpIoLib + BaseLib + DebugLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + +[Protocols] + gEfiTcp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiTcp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiTcp6ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiTcp6ProtocolGuid # PROTOCOL ALWAYS_CONSUMED diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 0530f91180..8cf4b75309 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -39,6 +39,10 @@ # This library is only intended to be used by UEFI network stack modules. UdpIoLib|Include/Library/UdpIoLib.h + ## @libraryclass The helper routines to access TCP service. + # This library is only intended to be used by UEFI network stack modules. + TcpIoLib|Include/Library/TcpIoLib.h + ## @libraryclass Defines a set of methods to reset whole system. ResetSystemLib|Include/Library/ResetSystemLib.h diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index d8a3826ef7..86ad3f521e 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -68,6 +68,7 @@ NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf + TcpIoLib|MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf -- 2.39.2