summaryrefslogtreecommitdiff
path: root/StdLib/EfiSocketLib
diff options
context:
space:
mode:
authorlpleahy <lpleahy@6f19259b-4bc3-4df7-8a09-765794883524>2011-09-30 23:02:35 +0000
committerlpleahy <lpleahy@6f19259b-4bc3-4df7-8a09-765794883524>2011-09-30 23:02:35 +0000
commita88c31639bb24c73383a4528a5b77066e805148b (patch)
tree058801cd8687b0a0c6f82459b56b2ad3beb43bf4 /StdLib/EfiSocketLib
parentdf7499fcc1fbd6c825cabf19bbed379688416125 (diff)
Update the sockets library code
* Passes conformance and functional tests. * Builds with GCC 4.4 compiler. Signed-off by: lpleahy git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12497 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'StdLib/EfiSocketLib')
-rw-r--r--StdLib/EfiSocketLib/DxeSupport.c322
-rw-r--r--StdLib/EfiSocketLib/EfiSocketLib.inf5
-rw-r--r--StdLib/EfiSocketLib/Init.c34
-rw-r--r--StdLib/EfiSocketLib/Ip4.c1264
-rw-r--r--StdLib/EfiSocketLib/ReleaseNotes.txt31
-rw-r--r--StdLib/EfiSocketLib/Service.c201
-rw-r--r--StdLib/EfiSocketLib/Socket.c5046
-rw-r--r--StdLib/EfiSocketLib/Socket.h1762
-rw-r--r--StdLib/EfiSocketLib/Tcp4.c2973
-rw-r--r--StdLib/EfiSocketLib/Udp4.c2264
-rw-r--r--StdLib/EfiSocketLib/UseEfiSocketLib.c138
11 files changed, 7973 insertions, 6067 deletions
diff --git a/StdLib/EfiSocketLib/DxeSupport.c b/StdLib/EfiSocketLib/DxeSupport.c
new file mode 100644
index 0000000000..284fa9cdfe
--- /dev/null
+++ b/StdLib/EfiSocketLib/DxeSupport.c
@@ -0,0 +1,322 @@
+/** @file
+ SocketDxe support routines
+
+ Copyright (c) 2011, 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 "Socket.h"
+
+
+/**
+ Creates a child handle and installs gEfiSocketProtocolGuid.
+
+ This routine creates a child handle for the socket driver and
+ installs the ::gEfiSocketProtocolGuid on that handle with a pointer
+ to the ::EFI_SOCKET_PROTOCOL structure address.
+
+ This routine is called by ::EslServiceGetProtocol in UseSocketDxe
+ when the socket application is linked with UseSocketDxe.
+
+ @param [in] pThis Address of the EFI_SERVICE_BINDING_PROTOCOL structure.
+ @param [in] pChildHandle Pointer to the handle of the child to create. If it is NULL,
+ then a new handle is created. If it is a pointer to an existing UEFI handle,
+ then the protocol is added to the existing UEFI handle.
+
+ @retval EFI_SUCCESS The protocol was added to ChildHandle.
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
+ the child
+ @retval other The child handle was not created
+
+**/
+EFI_STATUS
+EFIAPI
+EslDxeCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL * pThis,
+ IN OUT EFI_HANDLE * pChildHandle
+ )
+{
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Create a socket structure
+ //
+ Status = EslSocketAllocate ( pChildHandle,
+ DEBUG_SOCKET,
+ &pSocket );
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Removes gEfiSocketProtocolGuid and destroys the child handle.
+
+ This routine uninstalls ::gEfiSocketProtocolGuid from the child handle
+ and destroys the child handle if necessary.
+
+ This routine is called from ???.
+
+ @param [in] pThis Address of the EFI_SERVICE_BINDING_PROTOCOL structure.
+ @param [in] ChildHandle Handle of the child to destroy
+
+ @retval EFI_SUCCESS The protocol was removed from ChildHandle.
+ @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
+ @retval EFI_INVALID_PARAMETER Child handle is not a valid UEFI Handle.
+ @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
+ because its services are being used.
+ @retval other The child handle was not destroyed
+
+**/
+EFI_STATUS
+EFIAPI
+EslDxeDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL * pThis,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ ESL_LAYER * pLayer;
+ ESL_SOCKET * pSocket;
+ ESL_SOCKET * pSocketPrevious;
+ EFI_SOCKET_PROTOCOL * pSocketProtocol;
+ EFI_STATUS Status;
+ EFI_TPL TplPrevious;
+
+ DBG_ENTER ( );
+
+ //
+ // Locate the socket control structure
+ //
+ pLayer = &mEslLayer;
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiSocketProtocolGuid,
+ (VOID **)&pSocketProtocol,
+ pLayer->ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if ( !EFI_ERROR ( Status )) {
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
+
+ //
+ // Synchronize with the socket layer
+ //
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+
+ //
+ // Walk the socket list
+ //
+ pSocketPrevious = pLayer->pSocketList;
+ if ( NULL != pSocketPrevious ) {
+ if ( pSocket == pSocketPrevious ) {
+ //
+ // Remove the socket from the head of the list
+ //
+ pLayer->pSocketList = pSocket->pNext;
+ }
+ else {
+ //
+ // Find the socket in the middle of the list
+ //
+ while (( NULL != pSocketPrevious )
+ && ( pSocket != pSocketPrevious->pNext )) {
+ //
+ // Set the next socket
+ //
+ pSocketPrevious = pSocketPrevious->pNext;
+ }
+ if ( NULL != pSocketPrevious ) {
+ //
+ // Remove the socket from the middle of the list
+ //
+ pSocketPrevious = pSocket->pNext;
+ }
+ }
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL,
+ "ERROR - Socket list is empty!\r\n" ));
+ }
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+
+ //
+ // Determine if the socket was found
+ //
+ if ( NULL != pSocketPrevious ) {
+ pSocket->pNext = NULL;
+
+ //
+ // Remove the socket protocol
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandle,
+ &gEfiSocketProtocolGuid,
+ &pSocket->SocketProtocol,
+ NULL );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_POOL | DEBUG_INFO,
+ "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",
+ ChildHandle ));
+
+ //
+ // Free the socket structure
+ //
+ Status = gBS->FreePool ( pSocket );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_POOL,
+ "0x%08x: Free pSocket, %d bytes\r\n",
+ pSocket,
+ sizeof ( *pSocket )));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL,
+ "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
+ pSocket,
+ Status ));
+ }
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INFO,
+ "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
+ ChildHandle,
+ Status ));
+ }
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_INFO,
+ "ERROR - The socket was not in the socket list!\r\n" ));
+ Status = EFI_NOT_FOUND;
+ }
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to open socket protocol on 0x%08x, Status; %r\r\n",
+ ChildHandle,
+ Status ));
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+Install the socket service
+
+This routine installs the ::gEfiSocketServiceBindingProtocolGuid
+on the SocketDxe image handle to announce the availability
+of the socket layer to the rest of EFI.
+
+SocketDxe's EntryPoint routine calls this routine to
+make the socket layer available.
+
+@param [in] pImageHandle Address of the image handle
+
+@retval EFI_SUCCESS Service installed successfully
+**/
+EFI_STATUS
+EFIAPI
+EslDxeInstall (
+ IN EFI_HANDLE * pImageHandle
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install the socket service binding protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ pImageHandle,
+ &gEfiSocketServiceBindingProtocolGuid,
+ mEslLayer.pServiceBinding,
+ NULL
+ );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
+ "Installed: gEfiSocketServiceBindingProtocolGuid on 0x%08x\r\n",
+ *pImageHandle ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
+ "ERROR - InstallMultipleProtocolInterfaces failed, Status: %r\r\n",
+ Status ));
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+Uninstall the socket service
+
+This routine removes the gEfiSocketServiceBindingProtocolGuid from
+the SocketDxe image handle to notify EFI that the socket layer
+is no longer available.
+
+SocketDxe's DriverUnload routine calls this routine to remove the
+socket layer.
+
+@param [in] ImageHandle Handle for the image.
+
+@retval EFI_SUCCESS Service installed successfully
+**/
+EFI_STATUS
+EFIAPI
+EslDxeUninstall (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install the socket service binding protocol
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiSocketServiceBindingProtocolGuid,
+ mEslLayer.pServiceBinding,
+ NULL
+ );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_POOL | DEBUG_INIT,
+ "Removed: gEfiSocketServiceBindingProtocolGuid from 0x%08x\r\n",
+ ImageHandle ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
+ "ERROR - Failed to remove gEfiSocketServiceBindingProtocolGuid from 0x%08x, Status: %r\r\n",
+ ImageHandle,
+ Status ));
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
diff --git a/StdLib/EfiSocketLib/EfiSocketLib.inf b/StdLib/EfiSocketLib/EfiSocketLib.inf
index 6671e840f2..df639527f6 100644
--- a/StdLib/EfiSocketLib/EfiSocketLib.inf
+++ b/StdLib/EfiSocketLib/EfiSocketLib.inf
@@ -28,7 +28,9 @@
#
[Sources.common]
+ DxeSupport.c
Init.c
+ Ip4.c
Service.c
Socket.c
Tcp4.c
@@ -43,10 +45,13 @@
[LibraryClasses]
BaseMemoryLib
DebugLib
+ MemoryAllocationLib
UefiBootServicesTableLib
UefiLib
[Protocols]
+ gEfiIp4ProtocolGuid
+ gEfiIp4ServiceBindingProtocolGuid
gEfiTcp4ProtocolGuid
gEfiTcp4ServiceBindingProtocolGuid
gEfiUdp4ProtocolGuid
diff --git a/StdLib/EfiSocketLib/Init.c b/StdLib/EfiSocketLib/Init.c
index f444acc742..88d2065c21 100644
--- a/StdLib/EfiSocketLib/Init.c
+++ b/StdLib/EfiSocketLib/Init.c
@@ -18,7 +18,22 @@
/**
EFI Socket Library Constructor
- @retval EFI_SUCCESS The initialization was successful
+ This routine supports an implementation dependent constructor
+ depending upon whether the library is linked to a socket
+ application or the SocketDxe driver. The following modules
+ declare the redirection for the constructor in ::mpfnEslConstructor:
+ <ul>
+ <li>StdLib/EfiSocketLib/UseSocketLib.c - Application links against EfiSocketLib</li>
+ <li>StdLib/SocketDxe/EntryUnload.c - SocketDxe links against EfiSocketLib</li>
+ </ul>
+
+ The EfiSocketLib.inf file lists ::EslConstructor as the CONSTRUCTOR
+ in the [Defines] section. As a result, this routine is called by
+ the ProcessLibraryConstructorList routine of the AutoGen.c module
+ in the Build directory associated with the socket application or
+ the SocketDxe driver.
+
+ @retval EFI_SUCCESS The socket layer initialization was successful
**/
EFI_STATUS
@@ -54,7 +69,22 @@ EslConstructor (
/**
EFI Socket Library Destructor
- @retval EFI_SUCCESS The shutdown was successful
+ This routine supports an implementation dependent destructor
+ depending upon whether the library is linked to a socket
+ application or the SocketDxe driver. The following modules
+ declare the redirection for the destructor in ::mpfnEslDestructor:
+ <ul>
+ <li>StdLib/EfiSocketLib/UseSocketLib.c - Application links against EfiSocketLib</li>
+ <li>StdLib/SocketDxe/EntryUnload.c - SocketDxe links against EfiSocketLib</li>
+ </ul>
+
+ The EfiSocketLib.inf file lists ::EslDestructor as the DESTRUCTOR
+ in the [Defines] section. As a result, this routine is called by
+ the ProcessLibraryDestructorList routine of the AutoGen.c module
+ in the Build directory associated with the socket application or
+ the SocketDxe driver.
+
+ @retval EFI_SUCCESS The socket layer shutdown was successful
**/
EFI_STATUS
diff --git a/StdLib/EfiSocketLib/Ip4.c b/StdLib/EfiSocketLib/Ip4.c
new file mode 100644
index 0000000000..2d341269cc
--- /dev/null
+++ b/StdLib/EfiSocketLib/Ip4.c
@@ -0,0 +1,1264 @@
+/** @file
+ Implement the IP4 driver support for the socket layer.
+
+ Copyright (c) 2011, 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 "Socket.h"
+
+
+/**
+ Get the local socket address
+
+ This routine returns the IPv4 address associated with the local
+ socket.
+
+ This routine is called by ::EslSocketGetLocalAddress to determine the
+ network address for the SOCK_RAW socket.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [out] pAddress Network address to receive the local system address
+
+**/
+VOID
+EslIp4LocalAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
+ )
+{
+ struct sockaddr_in * pLocalAddress;
+ ESL_IP4_CONTEXT * pIp4;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the local address
+ //
+ pIp4 = &pPort->Context.Ip4;
+ pLocalAddress = (struct sockaddr_in *)pAddress;
+ pLocalAddress->sin_family = AF_INET;
+ CopyMem ( &pLocalAddress->sin_addr,
+ &pIp4->ModeData.ConfigData.StationAddress.Addr[0],
+ sizeof ( pLocalAddress->sin_addr ));
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Set the local port address.
+
+ This routine sets the local port address.
+
+ This support routine is called by ::EslSocketPortAllocate.
+
+ @param [in] pPort Address of an ESL_PORT structure
+ @param [in] pSockAddr Address of a sockaddr structure that contains the
+ connection point on the local machine. An IPv4 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv4 address restricts the connection to the
+ network stack supporting that address. Specifying zero
+ for the port causes the network layer to assign a port
+ number from the dynamic range. Specifying a specific
+ port number causes the network layer to use that port.
+
+ @param [in] bBindTest TRUE = run bind testing
+
+ @retval EFI_SUCCESS The operation was successful
+
+ **/
+EFI_STATUS
+EslIp4LocalAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest
+ )
+{
+ EFI_IP4_CONFIG_DATA * pConfig;
+ CONST struct sockaddr_in * pIpAddress;
+ CONST UINT8 * pIpv4Address;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Validate the address
+ //
+ pIpAddress = (struct sockaddr_in *)pSockAddr;
+ if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {
+ //
+ // The local address must not be the broadcast address
+ //
+ Status = EFI_INVALID_PARAMETER;
+ pPort->pSocket->errno = EADDRNOTAVAIL;
+ }
+ else {
+ Status = EFI_SUCCESS;
+
+ //
+ // Set the local address
+ //
+ pIpAddress = (struct sockaddr_in *)pSockAddr;
+ pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;
+ pConfig = &pPort->Context.Ip4.ModeData.ConfigData;
+ pConfig->StationAddress.Addr[0] = pIpv4Address[0];
+ pConfig->StationAddress.Addr[1] = pIpv4Address[1];
+ pConfig->StationAddress.Addr[2] = pIpv4Address[2];
+ pConfig->StationAddress.Addr[3] = pIpv4Address[3];
+
+ //
+ // Determine if the default address is used
+ //
+ pConfig->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );
+
+ //
+ // Display the local address
+ //
+ DEBUG (( DEBUG_BIND,
+ "0x%08x: Port, Local IP4 Address: %d.%d.%d.%d\r\n",
+ pPort,
+ pConfig->StationAddress.Addr[0],
+ pConfig->StationAddress.Addr[1],
+ pConfig->StationAddress.Addr[2],
+ pConfig->StationAddress.Addr[3]));
+
+ //
+ // Set the subnet mask
+ //
+ if ( pConfig->UseDefaultAddress ) {
+ pConfig->SubnetMask.Addr[0] = 0;
+ pConfig->SubnetMask.Addr[1] = 0;
+ pConfig->SubnetMask.Addr[2] = 0;
+ pConfig->SubnetMask.Addr[3] = 0;
+ }
+ else {
+ pConfig->SubnetMask.Addr[0] = 0xff;
+ pConfig->SubnetMask.Addr[1] = 0xff;
+ pConfig->SubnetMask.Addr[2] = 0xff;
+ pConfig->SubnetMask.Addr[3] = 0xff;
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Get the option value
+
+ This routine handles the IPv4 level options.
+
+ The ::EslSocketOptionGet routine calls this routine to retrieve
+ the IPv4 options one at a time by name.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
+ @param [in] OptionName Name of the option
+ @param [out] ppOptionData Buffer to receive address of option value
+ @param [out] pOptionLength Buffer to receive the option length
+
+ @retval EFI_SUCCESS - Socket data successfully received
+
+ **/
+EFI_STATUS
+EslIp4OptionGet (
+ IN ESL_SOCKET * pSocket,
+ IN int OptionName,
+ OUT CONST void ** __restrict ppOptionData,
+ OUT socklen_t * __restrict pOptionLength
+ )
+{
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+
+ //
+ // Attempt to get the option
+ //
+ switch ( OptionName ) {
+ default:
+ //
+ // Option not supported
+ //
+ pSocket->errno = ENOPROTOOPT;
+ Status = EFI_INVALID_PARAMETER;
+ break;
+
+ case IP_HDRINCL:
+ *ppOptionData = (void *)pSocket->bIncludeHeader;
+ *pOptionLength = sizeof ( pSocket->bIncludeHeader );
+ break;
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Set the option value
+
+ This routine handles the IPv4 level options.
+
+ The ::EslSocketOptionSet routine calls this routine to adjust
+ the IPv4 options one at a time by name.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
+ @param [in] OptionName Name of the option
+ @param [in] pOptionValue Buffer containing the option value
+ @param [in] OptionLength Length of the buffer in bytes
+
+ @retval EFI_SUCCESS - Option successfully set
+
+ **/
+EFI_STATUS
+EslIp4OptionSet (
+ IN ESL_SOCKET * pSocket,
+ IN int OptionName,
+ IN CONST void * pOptionValue,
+ IN socklen_t OptionLength
+ )
+{
+ BOOLEAN bTrueFalse;
+ socklen_t LengthInBytes;
+ UINT8 * pOptionData;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+
+ //
+ // Determine if the option protocol matches
+ //
+ LengthInBytes = 0;
+ pOptionData = NULL;
+ switch ( OptionName ) {
+ default:
+ //
+ // Protocol level not supported
+ //
+ DEBUG (( DEBUG_INFO | DEBUG_OPTION, "ERROR - Invalid protocol option\r\n" ));
+ pSocket->errno = ENOTSUP;
+ Status = EFI_UNSUPPORTED;
+ break;
+
+ case IP_HDRINCL:
+
+ //
+ // Validate the option length
+ //
+ if ( sizeof ( UINT32 ) == OptionLength ) {
+ //
+ // Restrict the input to TRUE or FALSE
+ //
+ bTrueFalse = TRUE;
+ if ( 0 == *(UINT32 *)pOptionValue ) {
+ bTrueFalse = FALSE;
+ }
+ pOptionValue = &bTrueFalse;
+
+ //
+ // Set the option value
+ //
+ pOptionData = (UINT8 *)&pSocket->bIncludeHeader;
+ LengthInBytes = sizeof ( pSocket->bIncludeHeader );
+ }
+ break;
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Free a receive packet
+
+ This routine performs the network specific operations necessary
+ to free a receive packet.
+
+ This routine is called by ::EslSocketPortCloseTxDone to free a
+ receive packet.
+
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
+ @param [in, out] pRxBytes Address of the count of RX bytes
+
+**/
+VOID
+EslIp4PacketFree (
+ IN ESL_PACKET * pPacket,
+ IN OUT size_t * pRxBytes
+ )
+{
+ EFI_IP4_RECEIVE_DATA * pRxData;
+ DBG_ENTER ( );
+
+ //
+ // Account for the receive bytes
+ //
+ pRxData = pPacket->Op.Ip4Rx.pRxData;
+ *pRxBytes -= pRxData->HeaderLength + pRxData->DataLength;
+
+ //
+ // Disconnect the buffer from the packet
+ //
+ pPacket->Op.Ip4Rx.pRxData = NULL;
+
+ //
+ // Return the buffer to the IP4 driver
+ //
+ gBS->SignalEvent ( pRxData->RecycleSignal );
+ DBG_EXIT ( );
+}
+
+
+/**
+ Initialize the network specific portions of an ::ESL_PORT structure.
+
+ This routine initializes the network specific portions of an
+ ::ESL_PORT structure for use by the socket.
+
+ This support routine is called by ::EslSocketPortAllocate
+ to connect the socket with the underlying network adapter
+ running the IPv4 protocol.
+
+ @param [in] pPort Address of an ESL_PORT structure
+ @param [in] DebugFlags Flags for debug messages
+
+ @retval EFI_SUCCESS - Socket successfully created
+
+ **/
+EFI_STATUS
+EslIp4PortAllocate (
+ IN ESL_PORT * pPort,
+ IN UINTN DebugFlags
+ )
+{
+ EFI_IP4_CONFIG_DATA * pConfig;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Initialize the port
+ //
+ pSocket = pPort->pSocket;
+ pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Ip4Tx.TxData );
+ pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Ip4Tx.Event );
+ pSocket->TxTokenOffset = OFFSET_OF ( EFI_IP4_COMPLETION_TOKEN, Packet.TxData );
+
+ //
+ // Save the cancel, receive and transmit addresses
+ //
+ pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.IPv4->Configure;
+ pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.IPv4->Cancel;
+ pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.IPv4->Receive;
+ pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.IPv4->Transmit;
+
+ //
+ // Set the configuration flags
+ //
+ pConfig = &pPort->Context.Ip4.ModeData.ConfigData;
+ pConfig->AcceptIcmpErrors = FALSE;
+ pConfig->AcceptBroadcast = FALSE;
+ pConfig->AcceptPromiscuous = FALSE;
+ pConfig->TypeOfService = 0;
+ pConfig->TimeToLive = 255;
+ pConfig->DoNotFragment = FALSE;
+ pConfig->RawData = FALSE;
+ pConfig->ReceiveTimeout = 0;
+ pConfig->TransmitTimeout = 0;
+
+ //
+ // Set the default protocol
+ //
+ pConfig->DefaultProtocol = (UINT8)pSocket->Protocol;
+ pConfig->AcceptAnyProtocol = (BOOLEAN)( 0 == pConfig->DefaultProtocol );
+ Status = EFI_SUCCESS;
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Receive data from a network connection.
+
+ This routine attempts to return buffered data to the caller. The
+ data is removed from the urgent queue if the message flag MSG_OOB
+ is specified, otherwise data is removed from the normal queue.
+ See the \ref ReceiveEngine section.
+
+ This routine is called by ::EslSocketReceive to handle the network
+ specific receive operation to support SOCK_RAW sockets.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
+
+ @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
+
+ @param [in] BufferLength Length of the the buffer
+
+ @param [in] pBuffer Address of a buffer to receive the data.
+
+ @param [in] pDataLength Number of received data bytes in the buffer.
+
+ @param [out] pAddress Network address to receive the remote system address
+
+ @param [out] pSkipBytes Address to receive the number of bytes skipped
+
+ @return Returns the address of the next free byte in the buffer.
+
+ **/
+UINT8 *
+EslIp4Receive (
+ IN ESL_PORT * pPort,
+ IN ESL_PACKET * pPacket,
+ IN BOOLEAN * pbConsumePacket,
+ IN size_t BufferLength,
+ IN UINT8 * pBuffer,
+ OUT size_t * pDataLength,
+ OUT struct sockaddr * pAddress,
+ OUT size_t * pSkipBytes
+ )
+{
+ size_t DataBytes;
+ size_t HeaderBytes;
+ size_t LengthInBytes;
+ struct sockaddr_in * pRemoteAddress;
+ EFI_IP4_RECEIVE_DATA * pRxData;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the remote system address if requested
+ //
+ pRxData = pPacket->Op.Ip4Rx.pRxData;
+ if ( NULL != pAddress ) {
+ //
+ // Build the remote address
+ //
+ DEBUG (( DEBUG_RX,
+ "Getting packet remote address: %d.%d.%d.%d\r\n",
+ pRxData->Header->SourceAddress.Addr[0],
+ pRxData->Header->SourceAddress.Addr[1],
+ pRxData->Header->SourceAddress.Addr[2],
+ pRxData->Header->SourceAddress.Addr[3]));
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pRxData->Header->SourceAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_addr ));
+ }
+
+ //
+ // Copy the IP header
+ //
+ HeaderBytes = pRxData->HeaderLength;
+ if ( HeaderBytes > BufferLength ) {
+ HeaderBytes = BufferLength;
+ }
+ DEBUG (( DEBUG_RX,
+ "0x%08x --> 0x%08x: Copy header 0x%08x bytes\r\n",
+ pRxData->Header,
+ pBuffer,
+ HeaderBytes ));
+ CopyMem ( pBuffer, pRxData->Header, HeaderBytes );
+ pBuffer += HeaderBytes;
+ LengthInBytes = HeaderBytes;
+
+ //
+ // Copy the received data
+ //
+ if ( 0 < ( BufferLength - LengthInBytes )) {
+ pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount,
+ &pRxData->FragmentTable[0],
+ BufferLength - LengthInBytes,
+ pBuffer,
+ &DataBytes );
+ LengthInBytes += DataBytes;
+ }
+
+ //
+ // Determine if the data is being read
+ //
+ if ( *pbConsumePacket ) {
+ //
+ // Display for the bytes consumed
+ //
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port account for 0x%08x bytes\r\n",
+ pPort,
+ LengthInBytes ));
+
+ //
+ // Account for any discarded data
+ //
+ *pSkipBytes = pRxData->HeaderLength + pRxData->DataLength - LengthInBytes;
+ }
+
+ //
+ // Return the data length and the buffer address
+ //
+ *pDataLength = LengthInBytes;
+ DBG_EXIT_HEX ( pBuffer );
+ return pBuffer;
+}
+
+
+/**
+ Get the remote socket address
+
+ This routine returns the address of the remote connection point
+ associated with the SOCK_RAW socket.
+
+ This routine is called by ::EslSocketGetPeerAddress to detemine
+ the IPv4 address associated with the network adapter.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [out] pAddress Network address to receive the remote system address
+
+**/
+VOID
+EslIp4RemoteAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
+ )
+{
+ struct sockaddr_in * pRemoteAddress;
+ ESL_IP4_CONTEXT * pIp4;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the remote address
+ //
+ pIp4 = &pPort->Context.Ip4;
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ pRemoteAddress->sin_family = AF_INET;
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pIp4->DestinationAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_addr ));
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Set the remote address
+
+ This routine sets the remote address in the port.
+
+ This routine is called by ::EslSocketConnect to specify the
+ remote network address.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [in] pSockAddr Network address of the remote system.
+
+ @param [in] SockAddrLength Length in bytes of the network address.
+
+ @retval EFI_SUCCESS The operation was successful
+
+ **/
+EFI_STATUS
+EslIp4RemoteAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN socklen_t SockAddrLength
+ )
+{
+ ESL_IP4_CONTEXT * pIp4;
+ CONST struct sockaddr_in * pRemoteAddress;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Set the remote address
+ //
+ pIp4 = &pPort->Context.Ip4;
+ pRemoteAddress = (struct sockaddr_in *)pSockAddr;
+ pIp4->DestinationAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
+ pIp4->DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
+ pIp4->DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
+ pIp4->DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
+ Status = EFI_SUCCESS;
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Process the receive completion
+
+ This routine keeps the IPv4 driver's buffer and queues it in
+ in FIFO order to the data queue. The IP4 driver's buffer will
+ be returned by either ::EslIp4Receive or ::EslSocketPortCloseTxDone.
+ See the \ref ReceiveEngine section.
+
+ This routine is called by the IPv4 driver when data is
+ received.
+
+ @param [in] Event The receive completion event
+
+ @param [in] pIo The address of an ::ESL_IO_MGMT structure
+
+**/
+VOID
+EslIp4RxComplete (
+ IN EFI_EVENT Event,
+ IN ESL_IO_MGMT * pIo
+ )
+{
+ size_t LengthInBytes;
+ ESL_PORT * pPort;
+ ESL_PACKET * pPacket;
+ EFI_IP4_RECEIVE_DATA * pRxData;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Get the operation status.
+ //
+ pPort = pIo->pPort;
+ Status = pIo->Token.Ip4Rx.Status;
+
+ //
+ // Get the packet length
+ //
+ pRxData = pIo->Token.Ip4Rx.Packet.RxData;
+ LengthInBytes = pRxData->HeaderLength + pRxData->DataLength;
+
+ //
+ // +--------------------+ +----------------------+
+ // | ESL_IO_MGMT | | Data Buffer |
+ // | | | (Driver owned) |
+ // | +---------------+ +----------------------+
+ // | | Token | ^
+ // | | Rx Event | |
+ // | | | +----------------------+
+ // | | RxData --> | EFI_IP4_RECEIVE_DATA |
+ // +----+---------------+ | (Driver owned) |
+ // +----------------------+
+ // +--------------------+ ^
+ // | ESL_PACKET | .
+ // | | .
+ // | +---------------+ .
+ // | | pRxData --> NULL .......
+ // +----+---------------+
+ //
+ //
+ // Save the data in the packet
+ //
+ pPacket = pIo->pPacket;
+ pPacket->Op.Ip4Rx.pRxData = pRxData;
+
+ //
+ // Complete this request
+ //
+ EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE );
+ DBG_EXIT ( );
+}
+
+
+/**
+ Determine if the socket is configured.
+
+ This routine uses the flag ESL_SOCKET::bConfigured to determine
+ if the network layer's configuration routine has been called.
+ This routine calls the ::EslSocketBind and configuration routines
+ if they were not already called. After the port is configured,
+ the \ref ReceiveEngine is started.
+
+ This routine is called by EslSocketIsConfigured to verify
+ that the socket is configured.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
+
+ @retval EFI_SUCCESS - The port is connected
+ @retval EFI_NOT_STARTED - The port is not connected
+
+ **/
+ EFI_STATUS
+ EslIp4SocketIsConfigured (
+ IN ESL_SOCKET * pSocket
+ )
+{
+ UINTN Index;
+ ESL_PORT * pPort;
+ ESL_PORT * pNextPort;
+ ESL_IP4_CONTEXT * pIp4;
+ EFI_IP4_PROTOCOL * pIp4Protocol;
+ EFI_STATUS Status;
+ struct sockaddr_in LocalAddress;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Configure the port if necessary
+ //
+ if ( !pSocket->bConfigured ) {
+ //
+ // Fill in the port list if necessary
+ //
+ if ( NULL == pSocket->pPortList ) {
+ LocalAddress.sin_len = sizeof ( LocalAddress );
+ LocalAddress.sin_family = AF_INET;
+ LocalAddress.sin_addr.s_addr = 0;
+ LocalAddress.sin_port = 0;
+ Status = EslSocketBind ( &pSocket->SocketProtocol,
+ (struct sockaddr *)&LocalAddress,
+ LocalAddress.sin_len,
+ &pSocket->errno );
+ }
+
+ //
+ // Walk the port list
+ //
+ pPort = pSocket->pPortList;
+ while ( NULL != pPort ) {
+ //
+ // Update the raw setting
+ //
+ pIp4 = &pPort->Context.Ip4;
+ if ( pSocket->bIncludeHeader ) {
+ //
+ // IP header will be included with the data on transmit
+ //
+ pIp4->ModeData.ConfigData.RawData = TRUE;
+ }
+
+ //
+ // Attempt to configure the port
+ //
+ pNextPort = pPort->pLinkSocket;
+ pIp4Protocol = pPort->pProtocol.IPv4;
+ DEBUG (( DEBUG_TX,
+ "0x%08x: pPort Configuring for %d.%d.%d.%d --> %d.%d.%d.%d\r\n",
+ pPort,
+ pIp4->ModeData.ConfigData.StationAddress.Addr[0],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[1],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[2],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[3],
+ pIp4->DestinationAddress.Addr[0],
+ pIp4->DestinationAddress.Addr[1],
+ pIp4->DestinationAddress.Addr[2],
+ pIp4->DestinationAddress.Addr[3]));
+ Status = pIp4Protocol->Configure ( pIp4Protocol,
+ &pIp4->ModeData.ConfigData );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Update the configuration data
+ //
+ Status = pIp4Protocol->GetModeData ( pIp4Protocol,
+ &pIp4->ModeData,
+ NULL,
+ NULL );
+ }
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_LISTEN,
+ "ERROR - Failed to configure the Ip4 port, Status: %r\r\n",
+ Status ));
+ switch ( Status ) {
+ case EFI_ACCESS_DENIED:
+ pSocket->errno = EACCES;
+ break;
+
+ default:
+ case EFI_DEVICE_ERROR:
+ pSocket->errno = EIO;
+ break;
+
+ case EFI_INVALID_PARAMETER:
+ pSocket->errno = EADDRNOTAVAIL;
+ break;
+
+ case EFI_NO_MAPPING:
+ pSocket->errno = EAFNOSUPPORT;
+ break;
+
+ case EFI_OUT_OF_RESOURCES:
+ pSocket->errno = ENOBUFS;
+ break;
+
+ case EFI_UNSUPPORTED:
+ pSocket->errno = EOPNOTSUPP;
+ break;
+ }
+ }
+ else {
+ DEBUG (( DEBUG_TX,
+ "0x%08x: pPort Configured for %d.%d.%d.%d --> %d.%d.%d.%d\r\n",
+ pPort,
+ pIp4->ModeData.ConfigData.StationAddress.Addr[0],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[1],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[2],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[3],
+ pIp4->DestinationAddress.Addr[0],
+ pIp4->DestinationAddress.Addr[1],
+ pIp4->DestinationAddress.Addr[2],
+ pIp4->DestinationAddress.Addr[3]));
+ DEBUG (( DEBUG_TX,
+ "Subnet Mask: %d.%d.%d.%d\r\n",
+ pIp4->ModeData.ConfigData.SubnetMask.Addr[0],
+ pIp4->ModeData.ConfigData.SubnetMask.Addr[1],
+ pIp4->ModeData.ConfigData.SubnetMask.Addr[2],
+ pIp4->ModeData.ConfigData.SubnetMask.Addr[3]));
+ DEBUG (( DEBUG_TX,
+ "Route Count: %d\r\n",
+ pIp4->ModeData.RouteCount ));
+ for ( Index = 0; pIp4->ModeData.RouteCount > Index; Index++ ) {
+ if ( 0 == Index ) {
+ DEBUG (( DEBUG_TX, "Route Table:\r\n" ));
+ }
+ DEBUG (( DEBUG_TX,
+ "%5d: %d.%d.%d.%d, %d.%d.%d.%d ==> %d.%d.%d.%d\r\n",
+ Index,
+ pIp4->ModeData.RouteTable[Index].SubnetAddress.Addr[0],
+ pIp4->ModeData.RouteTable[Index].SubnetAddress.Addr[1],
+ pIp4->ModeData.RouteTable[Index].SubnetAddress.Addr[2],
+ pIp4->ModeData.RouteTable[Index].SubnetAddress.Addr[3],
+ pIp4->ModeData.RouteTable[Index].SubnetMask.Addr[0],
+ pIp4->ModeData.RouteTable[Index].SubnetMask.Addr[1],
+ pIp4->ModeData.RouteTable[Index].SubnetMask.Addr[2],
+ pIp4->ModeData.RouteTable[Index].SubnetMask.Addr[3],
+ pIp4->ModeData.RouteTable[Index].GatewayAddress.Addr[0],
+ pIp4->ModeData.RouteTable[Index].GatewayAddress.Addr[1],
+ pIp4->ModeData.RouteTable[Index].GatewayAddress.Addr[2],
+ pIp4->ModeData.RouteTable[Index].GatewayAddress.Addr[3]));
+ }
+ pPort->bConfigured = TRUE;
+
+ //
+ // Start the first read on the port
+ //
+ EslSocketRxStart ( pPort );
+
+ //
+ // The socket is connected
+ //
+ pSocket->State = SOCKET_STATE_CONNECTED;
+ }
+
+ //
+ // Set the next port
+ //
+ pPort = pNextPort;
+ }
+
+ //
+ // Determine the configuration status
+ //
+ if ( NULL != pSocket->pPortList ) {
+ pSocket->bConfigured = TRUE;
+ }
+ }
+
+ //
+ // Determine the socket configuration status
+ //
+ if ( !EFI_ERROR ( Status )) {
+ Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
+ }
+
+ //
+ // Return the port connected state.
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Buffer data for transmission over a network connection.
+
+ This routine buffers data for the transmit engine in the normal
+ data queue. When the \ref TransmitEngine has resources, this
+ routine will start the transmission of the next buffer on the
+ network connection.
+
+ This routine is called by ::EslSocketTransmit to buffer
+ data for transmission. The data is copied into a local buffer
+ freeing the application buffer for reuse upon return. When
+ necessary, this routine starts the transmit engine that
+ performs the data transmission on the network connection. The
+ transmit engine transmits the data a packet at a time over the
+ network connection.
+
+ Transmission errors are returned during the next transmission or
+ during the close operation. Only buffering errors are returned
+ during the current transmission attempt.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
+
+ @param [in] Flags Message control flags
+
+ @param [in] BufferLength Length of the the buffer
+
+ @param [in] pBuffer Address of a buffer to receive the data.
+
+ @param [in] pDataLength Number of received data bytes in the buffer.
+
+ @param [in] pAddress Network address of the remote system address
+
+ @param [in] AddressLength Length of the remote network address structure
+
+ @retval EFI_SUCCESS - Socket data successfully buffered
+
+**/
+EFI_STATUS
+EslIp4TxBuffer (
+ IN ESL_SOCKET * pSocket,
+ IN int Flags,
+ IN size_t BufferLength,
+ IN CONST UINT8 * pBuffer,
+ OUT size_t * pDataLength,
+ IN const struct sockaddr * pAddress,
+ IN socklen_t AddressLength
+ )
+{
+ ESL_PACKET * pPacket;
+ ESL_PACKET * pPreviousPacket;
+ ESL_PORT * pPort;
+ const struct sockaddr_in * pRemoteAddress;
+ ESL_IP4_CONTEXT * pIp4;
+ size_t * pTxBytes;
+ ESL_IP4_TX_DATA * pTxData;
+ EFI_STATUS Status;
+ EFI_TPL TplPrevious;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume failure
+ //
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTCONN;
+ *pDataLength = 0;
+
+ //
+ // Verify that the socket is connected
+ //
+ if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
+ //
+ // Locate the port
+ //
+ pPort = pSocket->pPortList;
+ if ( NULL != pPort ) {
+ //
+ // Determine the queue head
+ //
+ pIp4 = &pPort->Context.Ip4;
+ pTxBytes = &pSocket->TxBytes;
+
+ //
+ // Verify that there is enough room to buffer another
+ // transmit operation
+ //
+ if ( pSocket->MaxTxBuf > *pTxBytes ) {
+ //
+ // Attempt to allocate the packet
+ //
+ Status = EslSocketPacketAllocate ( &pPacket,
+ sizeof ( pPacket->Op.Ip4Tx )
+ - sizeof ( pPacket->Op.Ip4Tx.Buffer )
+ + BufferLength,
+ 0,
+ DEBUG_TX );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Initialize the transmit operation
+ //
+ pTxData = &pPacket->Op.Ip4Tx;
+ pTxData->TxData.DestinationAddress.Addr[0] = pIp4->DestinationAddress.Addr[0];
+ pTxData->TxData.DestinationAddress.Addr[1] = pIp4->DestinationAddress.Addr[1];
+ pTxData->TxData.DestinationAddress.Addr[2] = pIp4->DestinationAddress.Addr[2];
+ pTxData->TxData.DestinationAddress.Addr[3] = pIp4->DestinationAddress.Addr[3];
+ pTxData->TxData.OverrideData = NULL;
+ pTxData->TxData.OptionsLength = 0;
+ pTxData->TxData.OptionsBuffer = NULL;
+ pTxData->TxData.TotalDataLength = (UINT32) BufferLength;
+ pTxData->TxData.FragmentCount = 1;
+ pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;
+ pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Ip4Tx.Buffer[0];
+
+ //
+ // Set the remote system address if necessary
+ //
+ if ( NULL != pAddress ) {
+ pRemoteAddress = (const struct sockaddr_in *)pAddress;
+ pTxData->Override.SourceAddress.Addr[0] = pIp4->ModeData.ConfigData.StationAddress.Addr[0];
+ pTxData->Override.SourceAddress.Addr[1] = pIp4->ModeData.ConfigData.StationAddress.Addr[1];
+ pTxData->Override.SourceAddress.Addr[2] = pIp4->ModeData.ConfigData.StationAddress.Addr[2];
+ pTxData->Override.SourceAddress.Addr[3] = pIp4->ModeData.ConfigData.StationAddress.Addr[3];
+ pTxData->TxData.DestinationAddress.Addr[0] = (UINT8)pRemoteAddress->sin_addr.s_addr;
+ pTxData->TxData.DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
+ pTxData->TxData.DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
+ pTxData->TxData.DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
+ pTxData->Override.GatewayAddress.Addr[0] = 0;
+ pTxData->Override.GatewayAddress.Addr[1] = 0;
+ pTxData->Override.GatewayAddress.Addr[2] = 0;
+ pTxData->Override.GatewayAddress.Addr[3] = 0;
+ pTxData->Override.Protocol = (UINT8)pSocket->Protocol;
+ pTxData->Override.TypeOfService = 0;
+ pTxData->Override.TimeToLive = 255;
+ pTxData->Override.DoNotFragment = FALSE;
+
+ //
+ // Use the remote system address when sending this packet
+ //
+ pTxData->TxData.OverrideData = &pTxData->Override;
+ }
+
+ //
+ // Copy the data into the buffer
+ //
+ CopyMem ( &pPacket->Op.Ip4Tx.Buffer[0],
+ pBuffer,
+ BufferLength );
+
+ //
+ // Synchronize with the socket layer
+ //
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+
+ //
+ // Stop transmission after an error
+ //
+ if ( !EFI_ERROR ( pSocket->TxError )) {
+ //
+ // Display the request
+ //
+ DEBUG (( DEBUG_TX,
+ "Send %d bytes from 0x%08x, %d.%d.%d.%d --> %d.%d.%d.%d\r\n",
+ BufferLength,
+ pBuffer,
+ pIp4->ModeData.ConfigData.StationAddress.Addr[0],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[1],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[2],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[3],
+ pTxData->TxData.DestinationAddress.Addr[0],
+ pTxData->TxData.DestinationAddress.Addr[1],
+ pTxData->TxData.DestinationAddress.Addr[2],
+ pTxData->TxData.DestinationAddress.Addr[3]));
+
+ //
+ // Queue the data for transmission
+ //
+ pPacket->pNext = NULL;
+ pPreviousPacket = pSocket->pTxPacketListTail;
+ if ( NULL == pPreviousPacket ) {
+ pSocket->pTxPacketListHead = pPacket;
+ }
+ else {
+ pPreviousPacket->pNext = pPacket;
+ }
+ pSocket->pTxPacketListTail = pPacket;
+ DEBUG (( DEBUG_TX,
+ "0x%08x: Packet on transmit list\r\n",
+ pPacket ));
+
+ //
+ // Account for the buffered data
+ //
+ *pTxBytes += BufferLength;
+ *pDataLength = BufferLength;
+
+ //
+ // Start the transmit engine if it is idle
+ //
+ if ( NULL != pPort->pTxFree ) {
+ EslSocketTxStart ( pPort,
+ &pSocket->pTxPacketListHead,
+ &pSocket->pTxPacketListTail,
+ &pPort->pTxActive,
+ &pPort->pTxFree );
+ }
+ }
+ else {
+ //
+ // Previous transmit error
+ // Stop transmission
+ //
+ Status = pSocket->TxError;
+ pSocket->errno = EIO;
+
+ //
+ // Free the packet
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_TX );
+ }
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+ }
+ else {
+ //
+ // Packet allocation failed
+ //
+ pSocket->errno = ENOMEM;
+ }
+ }
+ else {
+ //
+ // Not enough buffer space available
+ //
+ pSocket->errno = EAGAIN;
+ Status = EFI_NOT_READY;
+ }
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Process the transmit completion
+
+ This routine use ::EslSocketTxComplete to perform the transmit
+ completion processing for data packets.
+
+ This routine is called by the IPv4 network layer when a data
+ transmit request completes.
+
+ @param [in] Event The normal transmit completion event
+
+ @param [in] pIo The address of an ::ESL_IO_MGMT structure
+
+**/
+VOID
+EslIp4TxComplete (
+ IN EFI_EVENT Event,
+ IN ESL_IO_MGMT * pIo
+ )
+{
+ UINT32 LengthInBytes;
+ ESL_PORT * pPort;
+ ESL_PACKET * pPacket;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Locate the active transmit packet
+ //
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
+ pSocket = pPort->pSocket;
+
+ //
+ // Get the transmit length and status
+ //
+ LengthInBytes = pPacket->Op.Ip4Tx.TxData.TotalDataLength;
+ pSocket->TxBytes -= LengthInBytes;
+ Status = pIo->Token.Ip4Tx.Status;
+
+ //
+ // Complete the transmit operation
+ //
+ EslSocketTxComplete ( pIo,
+ LengthInBytes,
+ Status,
+ "Raw ",
+ &pSocket->pTxPacketListHead,
+ &pSocket->pTxPacketListTail,
+ &pPort->pTxActive,
+ &pPort->pTxFree );
+ DBG_EXIT ( );
+}
+
+
+/**
+ Interface between the socket layer and the network specific
+ code that supports SOCK_RAW sockets over IPv4.
+**/
+CONST ESL_PROTOCOL_API cEslIp4Api = {
+ "IPv4",
+ IPPROTO_IP,
+ OFFSET_OF ( ESL_PORT, Context.Ip4.ModeData.ConfigData ),
+ OFFSET_OF ( ESL_LAYER, pIp4List ),
+ OFFSET_OF ( struct sockaddr_in, sin_zero ),
+ sizeof ( struct sockaddr_in ),
+ AF_INET,
+ sizeof (((ESL_PACKET *)0 )->Op.Ip4Rx ),
+ sizeof (((ESL_PACKET *)0 )->Op.Ip4Rx ),
+ OFFSET_OF ( ESL_IO_MGMT, Token.Ip4Rx.Packet.RxData ),
+ FALSE,
+ EADDRNOTAVAIL,
+ NULL, // Accept
+ NULL, // ConnectPoll
+ NULL, // ConnectStart
+ EslIp4SocketIsConfigured,
+ EslIp4LocalAddressGet,
+ EslIp4LocalAddressSet,
+ NULL, // Listen
+ EslIp4OptionGet,
+ EslIp4OptionSet,
+ EslIp4PacketFree,
+ EslIp4PortAllocate,
+ NULL, // PortClose
+ NULL, // PortCloseOp
+ TRUE,
+ EslIp4Receive,
+ EslIp4RemoteAddressGet,
+ EslIp4RemoteAddressSet,
+ EslIp4RxComplete,
+ NULL, // RxStart
+ EslIp4TxBuffer,
+ EslIp4TxComplete,
+ NULL // TxOobComplete
+};
diff --git a/StdLib/EfiSocketLib/ReleaseNotes.txt b/StdLib/EfiSocketLib/ReleaseNotes.txt
new file mode 100644
index 0000000000..fd8ed74022
--- /dev/null
+++ b/StdLib/EfiSocketLib/ReleaseNotes.txt
@@ -0,0 +1,31 @@
+The following issues exist with the EFI Socket Library:
+
+* Don't run socket applications or the socket driver for a long time - The IPv4Config
+ and DHCP protocols are not properly running the renew and lease expiration timers.
+ When the DHCP lease expires it is possible for a duplicate IP address to exist on
+ the network. HSD 206136
+
+* Network adapters must be initialized prior to running the socket application - Static
+ and dynamic IP address need to be properly assigned to the network adapters on the
+ system. Note that sockets does not assign the IP addresses since it does not
+ understand how the system is connected to the network!
+
+* The default device must contain the Efi\etc directory populated with files containing
+ the proper network configuration - A template set of files is in StdLib\Efi\etc. Note
+ that the resolv.conf file contains the set of DNS servers.
+
+* Since DHCP is not running when the sockets application is running, the last negotiated
+ packet is no longer available. As a result, any of the options that DHCP did negotiate
+ are no longer available for sockets such as the list of DNS servers.
+
+* DHCP does not request the domain name and domain name server (DNS) addresses. This
+ requires that sockets use configuration files in Efi\etc!
+
+* TCPv4 transfer rate is slow (< 10 Mbits/sec) - This is an unidentified issue.
+
+* Raw socket applications are not able to pass the IP header as part of their
+ payload by using the IP option IP_HDRINCL. This is because the UEFI IPv4 driver
+ (Ip4Dxe) does not support RawData. HSD 206136
+
+* Only version 4 of the UEFI network stack is supported
+
diff --git a/StdLib/EfiSocketLib/Service.c b/StdLib/EfiSocketLib/Service.c
index 49c8884612..927f0e45b4 100644
--- a/StdLib/EfiSocketLib/Service.c
+++ b/StdLib/EfiSocketLib/Service.c
@@ -14,15 +14,16 @@
#include "Socket.h"
-EFI_TCP4_PROTOCOL * mpEfiTcpClose4 [ 1024 ];
-
/**
Connect to the network service bindings
Walk the network service protocols on the controller handle and
- locate any that are not in use. Create service structures to
- manage the service binding for the socket driver.
+ locate any that are not in use. Create ::ESL_SERVICE structures to
+ manage the network layer interfaces for the socket driver. Tag
+ each of the network interfaces that are being used. Finally, this
+ routine calls ESL_SOCKET_BINDING::pfnInitialize to prepare the network
+ interface for use by the socket layer.
@param [in] BindingHandle Handle for protocol binding.
@param [in] Controller Handle of device to work with.
@@ -40,11 +41,13 @@ EslServiceConnect (
{
BOOLEAN bInUse;
UINTN LengthInBytes;
- CONST DT_SOCKET_BINDING * pEnd;
+ UINT8 * pBuffer;
+ CONST ESL_SOCKET_BINDING * pEnd;
VOID * pJunk;
- VOID * pInterface;
- DT_SERVICE * pService;
- CONST DT_SOCKET_BINDING * pSocketBinding;
+ ESL_SERVICE ** ppServiceListHead;
+ ESL_SERVICE * pService;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -68,7 +71,7 @@ EslServiceConnect (
Status = gBS->OpenProtocol (
Controller,
pSocketBinding->pNetworkBinding,
- &pInterface,
+ (VOID**)&pServiceBinding,
BindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
@@ -108,7 +111,7 @@ EslServiceConnect (
pService->Signature = SERVICE_SIGNATURE;
pService->pSocketBinding = pSocketBinding;
pService->Controller = Controller;
- pService->pInterface = pInterface;
+ pService->pServiceBinding = pServiceBinding;
//
// Mark the controller in use
@@ -154,9 +157,13 @@ EslServiceConnect (
RAISE_TPL ( TplPrevious, TPL_SOCKETS );
//
- // Initialize the service
+ // Connect the service to the list
//
- Status = pSocketBinding->pfnInitialize ( pService );
+ pBuffer = (UINT8 *)&mEslLayer;
+ pBuffer = &pBuffer[ pSocketBinding->ServiceListOffset ];
+ ppServiceListHead = (ESL_SERVICE **)pBuffer;
+ pService->pNext = *ppServiceListHead;
+ *ppServiceListHead = pService;
//
// Release the socket layer synchronization
@@ -253,12 +260,13 @@ EslServiceConnect (
/**
- Shutdown the network connections to this controller by removing
- NetworkInterfaceIdentifier protocol and closing the DevicePath
- and PciIo protocols on Controller.
+ Shutdown the connections to the network layer by locating the
+ tags on the network interfaces established by ::EslServiceConnect.
+ This routine shutdowns any activity on the network interface and
+ then frees the ::ESL_SERVICE structures.
@param [in] BindingHandle Handle for protocol binding.
- @param [in] Controller Handle of device to stop driver on.
+ @param [in] Controller Handle of device to stop driver on.
@retval EFI_SUCCESS This driver is removed Controller.
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
@@ -272,9 +280,13 @@ EslServiceDisconnect (
IN EFI_HANDLE Controller
)
{
- CONST DT_SOCKET_BINDING * pEnd;
- DT_SERVICE * pService;
- CONST DT_SOCKET_BINDING * pSocketBinding;
+ UINT8 * pBuffer;
+ CONST ESL_SOCKET_BINDING * pEnd;
+ ESL_PORT * pPort;
+ ESL_SERVICE * pPreviousService;
+ ESL_SERVICE * pService;
+ ESL_SERVICE ** ppServiceListHead;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -310,9 +322,54 @@ EslServiceDisconnect (
RAISE_TPL ( TplPrevious, TPL_SOCKETS );
//
- // Shutdown the service
+ // Walk the list of ports
//
- pSocketBinding->pfnShutdown ( pService );
+ pPort = pService->pPortList;
+ while ( NULL != pPort ) {
+ //
+ // Remove the port from the port list
+ //
+ pPort->pService = NULL;
+ pService->pPortList = pPort->pLinkService;
+
+ //
+ // Close the port
+ //
+ EslSocketPortCloseStart ( pPort,
+ TRUE,
+ DEBUG_POOL | DEBUG_INIT );
+
+ //
+ // Set the next port
+ //
+ pPort = pService->pPortList;
+ }
+
+ //
+ // Remove the service from the service list
+ //
+ pBuffer = (UINT8 *)&mEslLayer;
+ pBuffer = &pBuffer[ pService->pSocketBinding->ServiceListOffset ];
+ ppServiceListHead = (ESL_SERVICE **)pBuffer;
+ pPreviousService = *ppServiceListHead;
+ if ( pService == pPreviousService ) {
+ //
+ // Remove the service from the beginning of the list
+ //
+ *ppServiceListHead = pService->pNext;
+ }
+ else {
+ //
+ // Remove the service from the middle of the list
+ //
+ while ( NULL != pPreviousService ) {
+ if ( pService == pPreviousService->pNext ) {
+ pPreviousService->pNext = pService->pNext;
+ break;
+ }
+ pPreviousService = pPreviousService->pNext;
+ }
+ }
//
// Release the socket layer synchronization
@@ -388,48 +445,6 @@ EslServiceDisconnect (
/**
-Install the socket service
-
-@param [in] pImageHandle Address of the image handle
-
-@retval EFI_SUCCESS Service installed successfully
-**/
-EFI_STATUS
-EFIAPI
-EslServiceInstall (
- IN EFI_HANDLE * pImageHandle
- )
-{
- EFI_STATUS Status;
-
- //
- // Install the socket service binding protocol
- //
- Status = gBS->InstallMultipleProtocolInterfaces (
- pImageHandle,
- &gEfiSocketServiceBindingProtocolGuid,
- &mEslLayer.ServiceBinding,
- NULL
- );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
- "Installed: gEfiSocketServiceBindingProtocolGuid on 0x%08x\r\n",
- *pImageHandle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
- "ERROR - InstallMultipleProtocolInterfaces failed, Status: %r\r\n",
- Status ));
- }
-
- //
- // Return the operation status
- //
- return Status;
-}
-
-
-/**
Initialize the service layer
@param [in] ImageHandle Handle for the image.
@@ -441,69 +456,20 @@ EslServiceLoad (
IN EFI_HANDLE ImageHandle
)
{
- DT_LAYER * pLayer;
+ ESL_LAYER * pLayer;
//
// Save the image handle
//
pLayer = &mEslLayer;
+ ZeroMem ( pLayer, sizeof ( *pLayer ));
pLayer->Signature = LAYER_SIGNATURE;
pLayer->ImageHandle = ImageHandle;
//
- // Initialize the TCP4 close
- //
- pLayer->TcpCloseMax4 = DIM ( mpEfiTcpClose4 );
- pLayer->ppTcpClose4 = mpEfiTcpClose4;
-
- //
// Connect the service binding protocol to the image handle
//
- pLayer->ServiceBinding.CreateChild = EslSocketCreateChild;
- pLayer->ServiceBinding.DestroyChild = EslSocketDestroyChild;
-}
-
-
-/**
-Uninstall the socket service
-
-@param [in] ImageHandle Handle for the image.
-
-@retval EFI_SUCCESS Service installed successfully
-**/
-EFI_STATUS
-EFIAPI
-EslServiceUninstall (
- IN EFI_HANDLE ImageHandle
- )
-{
- EFI_STATUS Status;
-
- //
- // Install the socket service binding protocol
- //
- Status = gBS->UninstallMultipleProtocolInterfaces (
- ImageHandle,
- &gEfiSocketServiceBindingProtocolGuid,
- &mEslLayer.ServiceBinding,
- NULL
- );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_POOL | DEBUG_INIT,
- "Removed: gEfiSocketServiceBindingProtocolGuid from 0x%08x\r\n",
- ImageHandle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
- "ERROR - Failed to remove gEfiSocketServiceBindingProtocolGuid from 0x%08x, Status: %r\r\n",
- ImageHandle,
- Status ));
- }
-
- //
- // Return the operation status
- //
- return Status;
+ pLayer->pServiceBinding = &mEfiServiceBinding;
}
@@ -517,13 +483,12 @@ EslServiceUnload (
VOID
)
{
- DT_LAYER * pLayer;
+ ESL_LAYER * pLayer;
//
// Undo the work by ServiceLoad
//
pLayer = &mEslLayer;
pLayer->ImageHandle = NULL;
- pLayer->ServiceBinding.CreateChild = NULL;
- pLayer->ServiceBinding.DestroyChild = NULL;
+ pLayer->pServiceBinding = NULL;
}
diff --git a/StdLib/EfiSocketLib/Socket.c b/StdLib/EfiSocketLib/Socket.c
index ebbc8df4d2..42e4689d0b 100644
--- a/StdLib/EfiSocketLib/Socket.c
+++ b/StdLib/EfiSocketLib/Socket.c
@@ -14,6 +14,446 @@
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ \section DataStructures Data Structures
+
+ <code><pre>
+
+ +-------------+ +-------------+ +-------------+
+ Service Lists | ::ESL_SERVICE |-->| ESL_SERVICE |-->| ESL_SERVICE |--> NULL (pNext)
+ +-------------+ +-------------+ +-------------+
+ ^ | (pPortList) |
+ pUdp4List ^ | pTcp4List | |
+ | | | |
+ ^ | | | |
+ pIp4List | | | | |
+ +---------------+ | |
+ | ::ESL_LAYER | ::mEslLayer | |
+ +---------------+ | |
+ | (pSocketList) | |
+ Socket List V V V
+ +-------------+ +-------------+ +-------------+
+ | ::ESL_SOCKET |-->| ::ESL_PORT |-->| ESL_PORT |--> NULL (pLinkSocket)
+ +-------------+ +-------------+ +-------------+
+ | | |
+ | | V
+ V V NULL
+ +-------------+ +-------------+
+ | ESL_SOCKET |-->| ESL_PORT |--> NULL
+ +-------------+ +-------------+
+ | | | | | |
+ V | | | | V
+ NULL | | | | NULL
+ (pNext) | | | | (pLinkService)
+ | | | | pRxPacketListHead
+ | | | `-----------------------------------------------.
+ | | | pRxOobPacketListHead |
+ | | `--------------------------------. |
+ | | pTxPacketListHead | |
+ | `---------------. | |
+ pTxOobPacketListHead | | | |
+ V V V V
+ +------------+ +------------+ +------------+ +------------+
+ | ::ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |
+ +------------+ +------------+ +------------+ +------------+
+ | | | |
+ V V V V
+ +------------+ +------------+ +------------+ +------------+
+ | ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |
+ +------------+ +------------+ +------------+ +------------+
+ | | | |
+ V V V V
+ NULL NULL NULL NULL
+ (pNext)
+
+ </pre></code>
+
+ ::mEslLayer is the one and only ::ESL_LAYER structure. It connects directly or
+ indirectly to the other data structures. The ESL_LAYER structure has a unique
+ service list for each of the network protocol interfaces.
+
+ ::ESL_SERVICE manages the network interfaces for a given transport type (IP4, TCP4, UDP4, etc.)
+
+ ::ESL_SOCKET manages the activity for a single socket instance. As such, it contains
+ the ::EFI_SOCKET_PROTOCOL structure which the BSD socket library uses as the object
+ reference and the API into the EFI socket library.
+
+ ::ESL_PORT manages the connection with a single instance of the lower layer network.
+ This structure is the socket equivalent of an IP connection or a TCP or UDP port.
+
+ ::ESL_PACKET buffers data for transmit and receive. There are four queues connected
+ to the ::ESL_SOCKET that manage the data:
+ <ul>
+ <li>ESL_SOCKET::pRxPacketListHead - Normal (low) priority receive data</li>
+ <li>ESL_SOCKET::pRxOobPacketListHead - High (out-of-band or urgent) priority receive data</li>
+ <li>ESL_SOCKET::pTxPacketListHead - Normal (low) priority transmit data</li>
+ <li>ESL_SOCKET::pTxOobPacketListHead - High (out-of-band or urgent) priority transmit data</li>
+ </ul>
+ The selection of the transmit queue is controlled by the MSG_OOB flag on the transmit
+ request as well as the socket option SO_OOBINLINE. The receive queue is selected by
+ the URGENT data flag for TCP and the setting of the socket option SO_OOBINLINE.
+
+ Data structure synchronization is done by raising TPL to TPL_SOCKET. Modifying
+ critical elements within the data structures must be done at this TPL. TPL is then
+ restored to the previous level. Note that the code verifies that all callbacks are
+ entering at TPL_SOCKETS for proper data structure synchronization.
+
+ \section PortCloseStateMachine Port Close State Machine
+
+ The port close state machine walks the port through the necessary
+ states to stop activity on the port and get it into a state where
+ the resources may be released. The state machine consists of the
+ following arcs and states:
+
+ <code><pre>
+
+ +--------------------------+
+ | Open |
+ +--------------------------+
+ |
+ | ::EslSocketPortCloseStart
+ V
+ +--------------------------+
+ | PORT_STATE_CLOSE_STARTED |
+ +--------------------------+
+ |
+ | ::EslSocketPortCloseTxDone
+ V
+ +--------------------------+
+ | PORT_STATE_CLOSE_TX_DONE |
+ +--------------------------+
+ |
+ | ::EslSocketPortCloseComplete
+ V
+ +--------------------------+
+ | PORT_STATE_CLOSE_DONE |
+ +--------------------------+
+ |
+ | ::EslSocketPortCloseRxDone
+ V
+ +--------------------------+
+ | PORT_STATE_CLOSE_RX_DONE |
+ +--------------------------+
+ |
+ | ::EslSocketPortClose
+ V
+ +--------------------------+
+ | Closed |
+ +--------------------------+
+
+ </pre></code>
+
+ <ul>
+ <li>Arc: ::EslSocketPortCloseStart - Marks the port as closing and
+ initiates the port close operation</li>
+ <li>State: PORT_STATE_CLOSE_STARTED</li>
+ <li>Arc: ::EslSocketPortCloseTxDone - Waits until all of the transmit
+ operations to complete. After all of the transmits are complete,
+ this routine initiates the network specific close operation by calling
+ through ESL_PROTOCOL_API::pfnPortCloseOp. One such routine is
+ ::EslTcp4PortCloseOp.
+ </li>
+ <li>State: PORT_STATE_CLOSE_TX_DONE</li>
+ <li>Arc: ::EslSocketPortCloseComplete - Called when the close operation is
+ complete. After the transition to PORT_STATE_CLOSE_DONE,
+ this routine calls ::EslSocketRxCancel to abort the pending receive operations.
+ </li>
+ <li>State: PORT_STATE_CLOSE_DONE</li>
+ <li>Arc: ::EslSocketPortCloseRxDone - Waits until all of the receive
+ operation have been cancelled. After the transition to
+ PORT_STATE_CLOSE_RX_DONE, this routine calls ::EslSocketPortClose.
+ </li>
+ <li>State: PORT_STATE_CLOSE_RX_DONE</li>
+ <li>Arc: ::EslSocketPortClose - This routine discards any receive buffers
+ using a network specific support routine via ESL_PROTOCOL_API::pfnPacketFree.
+ This routine then releases the port resources allocated by ::EslSocketPortAllocate
+ and calls the network specific port close routine (e.g. ::EslTcp4PortClose)
+ via ESL_PROTOCOL_API::pfnPortClose to release any network specific resources.
+ </li>
+ </ul>
+
+
+ \section ReceiveEngine Receive Engine
+
+ The receive path accepts data from the network and queues (buffers) it for the
+ application. Flow control is applied once a maximum amount of buffering is reached
+ and is released when the buffer usage drops below that limit. Eventually the
+ application requests data from the socket which removes entries from the queue and
+ returns the data.
+
+ The receive engine is the state machine which reads data from the network and
+ fills the queue with received packets. The receive engine uses two data structures
+ to manage the network receive opeations and the buffers.
+
+ At a high level, the ::ESL_IO_MGMT structures are managing the tokens and
+ events for the interface to the UEFI network stack. The ::ESL_PACKET
+ structures are managing the receive data buffers. The receive engine
+ connects these two structures in the network specific receive completion
+ routines.
+
+<code><pre>
+
+ +------------------+
+ | ::ESL_PORT |
+ | |
+ +------------------+
+ | ::ESL_IO_MGMT |
+ +------------------+
+ | ESL_IO_MGMT |
+ +------------------+
+ . .
+ . ESL_IO_MGMT .
+ . .
+ +------------------+
+
+</pre></code>
+
+ The ::ESL_IO_MGMT structures are allocated as part of the ::ESL_PORT structure in
+ ::EslSocketPortAllocate. The ESL_IO_MGMT structures are separated and placed on
+ the free list by calling ::EslSocketIoInit. The ESL_IO_MGMT structure contains
+ the network layer specific receive completion token and event. The receive engine
+ is eventually shutdown by ::EslSocketPortCloseTxDone and the resources in these
+ structures are released in ::EslSocketPortClose by a call to ::EslSocketIoFree.
+
+<code><pre>
+
+ pPort->pRxActive
+ |
+ V
+ +-------------+ +-------------+ +-------------+
+ Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ +-------------+ +-------------+ +-------------+
+
+ +-------------+ +-------------+ +-------------+
+ Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ +-------------+ +-------------+ +-------------+
+ ^
+ |
+ pPort->pRxFree
+</pre></code>
+
+ The receive engine is started by calling ::EslSocketRxStart. Flow control pauses
+ the receive engine by stopping the calls to EslSocketRxStart when the amount of
+ receive data waiting for the application meets or exceeds MAX_RX_DATA. After
+ the application reads enough data that the amount of buffering drops below this
+ limit, the calls to EslSockeRxStart continue which releases the flow control.
+
+ Receive flow control is applied when the port is created, since no receive
+ operation are pending to the low layer network driver. The flow control gets
+ released when the low layer network port is configured or the first receive
+ operation is posted. Flow control remains in the released state until the
+ maximum buffer space is consumed. During this time, ::EslSocketRxComplete
+ calls ::EslSocketRxStart. Flow control is applied in EslSocketRxComplete
+ by skipping the call to EslSocketRxStart. Flow control is eventually
+ released in ::EslSocketReceive when the buffer space drops below the
+ maximum amount causing EslSocketReceive to call EslSocketRxStart.
+
+<code><pre>
+
+ +------------+ +------------+
+ High .----->| ESL_PACKET |-->| ESL_PACKET |--> NULL (pNext)
+ Priority | +------------+ +------------+
+ |
+ | pRxOobPacketListHead
+ +------------+
+ | ::ESL_SOCKET |
+ +------------+
+ | pRxPacketListHead
+ Low |
+ Priority | +------------+ +------------+ +------------+
+ `----->| ::ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
+ +------------+ +------------+ +------------+
+
+</pre></code>
+
+ ::EslSocketRxStart connects an ::ESL_PACKET structure to the ::ESL_IO_MGMT structure
+ and then calls the network layer to start the receive operation. Upon
+ receive completion, ::EslSocketRxComplete breaks the connection between these
+ structrues and places the ESL_IO_MGMT structure onto the ESL_PORT::pRxFree list to
+ make token and event available for another receive operation. EslSocketRxComplete
+ then queues the ESL_PACKET structure (data packet) to either the
+ ESL_SOCKET::pRxOobPacketListTail or ESL_SOCKET::pRxPacketListTail depending on
+ whether urgent or normal data was received. Finally ::EslSocketRxComplete attempts
+ to start another receive operation.
+
+<code><pre>
+
+ Setup for IP4 and UDP4
+
+ +--------------------+
+ | ESL_IO_MGMT |
+ | |
+ | +---------------+
+ | | Token |
+ | | RxData --> NULL
+ +----+---------------+
+ |
+ V
+ +--------------------+
+ | ESL_PACKET |
+ | |
+ | +---------------+
+ | | pRxData --> NULL
+ +----+---------------+
+
+ Completion for IP4 and UDP4
+
+ +--------------------+ +----------------------+
+ | ESL_IO_MGMT | | Data Buffer |
+ | | | (Driver owned) |
+ | +---------------+ +----------------------+
+ | | Token | ^
+ | | Rx Event | |
+ | | | +----------------------+
+ | | RxData --> | EFI_IP4_RECEIVE_DATA |
+ +----+---------------+ | (Driver owned) |
+ | +----------------------+
+ V ^
+ +--------------------+ .
+ | ESL_PACKET | .
+ | | .
+ | +---------------+ .
+ | | pRxData --> NULL .......
+ +----+---------------+
+
+
+ Setup and completion for TCP4
+
+ +--------------------+ +--------------------------+
+ | ESL_IO_MGMT |-->| ESL_PACKET |
+ | | | |
+ | +---------------+ +----------------------+ |
+ | | Token | | EFI_IP4_RECEIVE_DATA | |
+ | | RxData --> | | |
+ | | | +----------------------+---+
+ | | Event | | Data Buffer |
+ +----+---------------+ | |
+ | |
+ +--------------------------+
+
+</pre></code>
+
+ To minimize the number of buffer copies, the data is not copied until the
+ application makes a receive call. At this point socket performs a single copy
+ in the receive path to move the data from the buffer filled by the network layer
+ into the application's buffer.
+
+ The IP4 and UDP4 drivers go one step further to reduce buffer copies. They
+ allow the socket layer to hold on to the actual receive buffer until the
+ application has performed a receive operation or closes the socket. Both
+ of theses operations return the buffer to the lower layer network driver
+ by calling ESL_PROTOCOL_API::pfnPacketFree.
+
+ When a socket application wants to receive data it indirectly calls
+ ::EslSocketReceive to remove data from one of the receive data queues. This routine
+ removes the next available packet from ESL_SOCKET::pRxOobPacketListHead or
+ ESL_SOCKET::pRxPacketListHead and copies the data from the packet
+ into the application's buffer. For SOCK_STREAM sockets, if the packet
+ contains more data then the ESL_PACKET structures remains at the head of the
+ receive queue for the next application receive
+ operation. For SOCK_DGRAM, SOCK_RAW and SOCK_SEQ_PACKET sockets, the ::ESL_PACKET
+ structure is removed from the head of the receive queue and any remaining data is
+ discarded as the packet is placed on the free queue.
+
+ During socket layer shutdown, ::EslSocketShutdown calls ::EslSocketRxCancel to
+ cancel any pending receive operations. EslSocketRxCancel calls the network specific
+ cancel routine using ESL_PORT::pfnRxCancel.
+
+
+ \section TransmitEngine Transmit Engine
+
+ Application calls to ::EslSocketTransmit cause data to be copied into a buffer.
+ The buffer exists as an extension to an ESL_PACKET structure and the structure
+ is placed at the end of the transmit queue.
+
+<code><pre>
+
+ *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
+ |
+ V
+ +------------+ +------------+ +------------+
+ Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
+ +------------+ +------------+ +------------+
+ ^
+ |
+ *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
+
+</pre></code>
+
+ There are actually two transmit queues the normal or low priority queue which is
+ the default and the urgent or high priority queue which is addressed by specifying
+ the MSG_OOB flag during the transmit request. Associated with each queue is a
+ transmit engine which is responsible for sending the data in that queue.
+
+ The transmit engine is the state machine which removes entries from the head
+ of the transmit queue and causes the data to be sent over the network.
+
+<code><pre>
+
+ +--------------------+ +--------------------+
+ | ESL_IO_MGMT | | ESL_PACKET |
+ | | | |
+ | +---------------+ +----------------+ |
+ | | Token | | Buffer Length | |
+ | | TxData --> | Buffer Address | |
+ | | | +----------------+---+
+ | | Event | | Data Buffer |
+ +----+---------------+ | |
+ +--------------------+
+</pre></code>
+
+ At a high level, the transmit engine uses a couple of data structures
+ to manage the data flow. The ::ESL_IO_MGMT structures manage the tokens and
+ events for the interface to the UEFI network stack. The ::ESL_PACKET
+ structures manage the data buffers that get sent. The transmit
+ engine connects these two structures prior to transmission and disconnects
+ them upon completion.
+
+<code><pre>
+
+ pPort->pTxActive or pTxOobActive
+ |
+ V
+ +-------------+ +-------------+ +-------------+
+ Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ +-------------+ +-------------+ +-------------+
+
+ +-------------+ +-------------+ +-------------+
+ Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ +-------------+ +-------------+ +-------------+
+ ^
+ |
+ pPort->pTxFree or pTxOobFree
+
+</pre></code>
+
+ The transmit engine manages multiple transmit operations using the
+ active and free lists shown above. ::EslSocketPortAllocate allocates the
+ ::ESL_IO_MGMT structures as an extension to the ::ESL_PORT structure.
+ This routine places the ESL_IO_MGMT structures on the free list by calling
+ ::EslSocketIoInit. During their lifetime, the ESL_IO_MGMT structures
+ will move from the free list to the active list and back again. The
+ active list contains the packets that are actively being processed by
+ the UEFI network stack. Eventually the ESL_IO_MGMT structures will be
+ removed from the free list and be deallocated by the EslSocketPortClose
+ routine.
+
+ The network specific code calls the ::EslSocketTxStart routine
+ to hand a packet to the network stack. EslSocketTxStart connects
+ the transmit packet (::ESL_PACKET) to an ::ESL_IO_MGMT structure
+ and then queues the result to one of the active lists:
+ ESL_PORT::pTxActive or ESL_PORT::pTxOobActive. The routine then
+ hands the packet to the network stack.
+
+ Upon completion, the network specific TxComplete routine calls
+ ::EslSocketTxComplete to disconnect the transmit packet from the
+ ESL_IO_MGMT structure and frees the ::ESL_PACKET structure by calling
+ ::EslSocketPacketFree. The routine places the ::ESL_IO_MGMT structure
+ into the free list either ESL_PORT::pTxFree or ESL_PORT::pTxOobFree.
+ EslSocketTxComplete then starts the next transmit operation while
+ the socket is active or calls the ::EslSocketPortCloseTxDone routine
+ when the socket is shutting down.
+
**/
#include "Socket.h"
@@ -24,62 +464,92 @@
List the network stack connection points for the socket driver.
**/
-CONST DT_SOCKET_BINDING cEslSocketBinding [] = {
+CONST ESL_SOCKET_BINDING cEslSocketBinding[] = {
+ { L"Ip4",
+ &gEfiIp4ServiceBindingProtocolGuid,
+ &gEfiIp4ProtocolGuid,
+ &mEslIp4ServiceGuid,
+ OFFSET_OF ( ESL_LAYER, pIp4List ),
+ 4, // RX buffers
+ 4, // TX buffers
+ 0 }, // TX Oob buffers
{ L"Tcp4",
&gEfiTcp4ServiceBindingProtocolGuid,
+ &gEfiTcp4ProtocolGuid,
&mEslTcp4ServiceGuid,
- EslTcpInitialize4,
- EslTcpShutdown4 },
+ OFFSET_OF ( ESL_LAYER, pTcp4List ),
+ 4, // RX buffers
+ 4, // TX buffers
+ 4 }, // TX Oob buffers
{ L"Udp4",
&gEfiUdp4ServiceBindingProtocolGuid,
+ &gEfiUdp4ProtocolGuid,
&mEslUdp4ServiceGuid,
- EslUdpInitialize4,
- EslUdpShutdown4 }
+ OFFSET_OF ( ESL_LAYER, pUdp4List ),
+ 4, // RX buffers
+ 4, // TX buffers
+ 0 } // TX Oob buffers
};
CONST UINTN cEslSocketBindingEntries = DIM ( cEslSocketBinding );
-DT_LAYER mEslLayer;
+/**
+ APIs to support the various socket types for the v4 network stack.
+**/
+CONST ESL_PROTOCOL_API * cEslAfInetApi[] = {
+ NULL, // 0
+ &cEslTcp4Api, // SOCK_STREAM
+ &cEslUdp4Api, // SOCK_DGRAM
+ &cEslIp4Api, // SOCK_RAW
+ NULL, // SOCK_RDM
+ &cEslTcp4Api // SOCK_SEQPACKET
+};
+
+/**
+ Number of entries in the v4 API array ::cEslAfInetApi.
+**/
+CONST int cEslAfInetApiSize = DIM ( cEslAfInetApi );
+
+
+/**
+ APIs to support the various socket types for the v6 network stack.
+**/
+CONST ESL_PROTOCOL_API * cEslAfInet6Api[] = {
+ NULL, // 0
+ NULL, // SOCK_STREAM
+ NULL, // SOCK_DGRAM
+ NULL, // SOCK_RAW
+ NULL, // SOCK_RDM
+ NULL // SOCK_SEQPACKET
+};
+
+/**
+ Number of entries in the v6 API array ::cEslAfInet6Api.
+**/
+CONST int cEslAfInet6ApiSize = DIM ( cEslAfInet6Api );
+
+
+/**
+ Global management structure for the socket layer.
+**/
+ESL_LAYER mEslLayer;
/**
Initialize an endpoint for network communication.
- The ::Socket routine initializes the communication endpoint by providing
- the support for the socket library function ::socket. The
- <a href="http://www.linuxhowtos.org/manpages/2/socket.htm">Linux</a>,
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html">POSIX</a>
- and <a href="http://msdn.microsoft.com/en-us/library/ms740506(v=VS.85).aspx">Windows</a>
- documentation for the socket routine are available online for reference.
+ This routine initializes the communication endpoint.
+
+ The ::socket routine calls this routine indirectly to create
+ the communication endpoint.
@param [in] pSocketProtocol Address of the socket protocol structure.
@param [in] domain Select the family of protocols for the client or server
- application.
-
- @param [in] type Specifies how to make the network connection. The following values
- are supported:
- <ul>
- <li>
- SOCK_STREAM - Connect to TCP, provides a byte stream
- that is manipluated by read, recv, send and write.
- </li>
- <li>
- SOCK_SEQPACKET - Connect to TCP, provides sequenced packet stream
- that is manipulated by read, recv, send and write.
- </li>
- <li>
- SOCK_DGRAM - Connect to UDP, provides a datagram service that is
- manipulated by recvfrom and sendto.
- </li>
- </ul>
-
- @param [in] protocol Specifies the lower layer protocol to use. The following
- values are supported:
- <ul>
- <li>IPPROTO_TCP</li> - This value must be combined with SOCK_STREAM.</li>
- <li>IPPROTO_UDP</li> - This value must be combined with SOCK_DGRAM.</li>
- </ul>
-
+ application. See the ::socket documentation for values.
+ @param [in] type Specifies how to make the network connection.
+ See the ::socket documentation for values.
+ @param [in] protocol Specifies the lower layer protocol to use.
+ See the ::socket documentation for values.
@param [out] pErrno Address to receive the errno value upon completion.
@retval EFI_SUCCESS - Socket successfully created
@@ -97,7 +567,11 @@ EslSocket (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ CONST ESL_PROTOCOL_API * pApi;
+ CONST ESL_PROTOCOL_API ** ppApiArray;
+ CONST ESL_PROTOCOL_API ** ppApiArrayEnd;
+ int ApiArraySize;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
int errno;
@@ -129,16 +603,30 @@ EslSocket (
// Validate the domain value
//
if (( AF_INET != domain )
- && ( AF_LOCAL != domain ))
- {
+ && ( AF_LOCAL != domain )) {
DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
- "ERROR - Invalid domain value" ));
+ "ERROR - Invalid domain value\r\n" ));
Status = EFI_INVALID_PARAMETER;
errno = EAFNOSUPPORT;
break;
}
//
+ // Determine the protocol APIs
+ //
+ ppApiArray = NULL;
+ ApiArraySize = 0;
+ if (( AF_INET == domain )
+ || ( AF_LOCAL == domain )) {
+ ppApiArray = &cEslAfInetApi[0];
+ ApiArraySize = cEslAfInetApiSize;
+ }
+ else {
+ ppApiArray = &cEslAfInet6Api[0];
+ ApiArraySize = cEslAfInet6ApiSize;
+ }
+
+ //
// Set the default type if necessary
//
if ( 0 == type ) {
@@ -148,46 +636,81 @@ EslSocket (
//
// Validate the type value
//
- if (( SOCK_STREAM == type )
- || ( SOCK_SEQPACKET == type )) {
- //
- // Set the default protocol if necessary
- //
- if ( 0 == protocol ) {
- protocol = IPPROTO_TCP;
- }
- }
- else if ( SOCK_DGRAM == type ) {
+ if (( type >= ApiArraySize )
+ || ( NULL == ppApiArray )
+ || ( NULL == ppApiArray[ type ])) {
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
+ "ERROR - Invalid type value\r\n" ));
//
- // Set the default protocol if necessary
+ // The socket type is not supported
//
- if ( 0 == protocol ) {
- protocol = IPPROTO_UDP;
- }
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
- "ERROR - Invalid type value" ));
Status = EFI_INVALID_PARAMETER;
- errno = EINVAL;
+ errno = EPROTOTYPE;
break;
}
//
+ // Set the default protocol if necessary
+ //
+ pApi = ppApiArray[ type ];
+ if ( 0 == protocol ) {
+ protocol = pApi->DefaultProtocol;
+ }
+
+ //
// Validate the protocol value
//
- if (( IPPROTO_TCP != protocol )
- && ( IPPROTO_UDP != protocol )) {
- DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
- "ERROR - Invalid protocol value" ));
+ if (( pApi->DefaultProtocol != protocol )
+ && ( SOCK_RAW != type )) {
Status = EFI_INVALID_PARAMETER;
- errno = EINVAL;
+
+ //
+ // Assume that the driver supports this protocol
+ //
+ ppApiArray = &cEslAfInetApi[0];
+ ppApiArrayEnd = &ppApiArray [ cEslAfInetApiSize ];
+ while ( ppApiArrayEnd > ppApiArray ) {
+ pApi = *ppApiArray;
+ if ( protocol == pApi->DefaultProtocol ) {
+ break;
+ }
+ ppApiArray += 1;
+ }
+ if ( ppApiArrayEnd <= ppApiArray ) {
+ //
+ // Verify against the IPv6 table
+ //
+ ppApiArray = &cEslAfInet6Api[0];
+ ppApiArrayEnd = &ppApiArray [ cEslAfInet6ApiSize ];
+ while ( ppApiArrayEnd > ppApiArray ) {
+ pApi = *ppApiArray;
+ if ( protocol == pApi->DefaultProtocol ) {
+ break;
+ }
+ ppApiArray += 1;
+ }
+ }
+ if ( ppApiArrayEnd <= ppApiArray ) {
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
+ "ERROR - The protocol is not supported!\r\n" ));
+ errno = EPROTONOSUPPORT;
+ break;
+ }
+
+ //
+ // The driver does not support this protocol
+ //
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
+ "ERROR - The protocol does not support this socket type!\r\n" ));
+ errno = EPROTONOSUPPORT;
+ errno = EPROTOTYPE;
break;
}
//
// Save the socket attributes
//
+ pSocket->pApi = pApi;
pSocket->Domain = domain;
pSocket->Type = type;
pSocket->Protocol = protocol;
@@ -212,11 +735,16 @@ EslSocket (
/**
Accept a network connection.
- The SocketAccept routine waits for a network connection to the socket.
- It is able to return the remote network address to the caller if
- requested.
+ This routine calls the network specific layer to remove the next
+ connection from the FIFO.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::accept calls this routine to poll for a network
+ connection to the socket. When a connection is available
+ this routine returns the ::EFI_SOCKET_PROTOCOL structure address
+ associated with the new socket and the remote network address
+ if requested.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] pSockAddr Address of a buffer to receive the remote
network address.
@@ -225,8 +753,9 @@ EslSocket (
On output specifies the length of the
remote network address.
- @param [out] ppSocketProtocol Address of a buffer to receive the socket protocol
- instance associated with the new socket.
+ @param [out] ppSocketProtocol Address of a buffer to receive the
+ ::EFI_SOCKET_PROTOCOL instance
+ associated with the new socket.
@param [out] pErrno Address to receive the errno value upon completion.
@@ -243,8 +772,8 @@ EslSocketAccept (
IN int * pErrno
)
{
- DT_SOCKET * pNewSocket;
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pNewSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -264,134 +793,122 @@ EslSocketAccept (
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
//
- // Validate the sockaddr
+ // Verify the API
//
- if (( NULL != pSockAddr )
- && ( NULL == pSockAddrLength )) {
- DEBUG (( DEBUG_ACCEPT,
- "ERROR - pSockAddr is NULL!\r\n" ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EFAULT;
+ if ( NULL == pSocket->pApi->pfnAccept ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
}
else {
//
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
+ // Validate the sockaddr
//
- // Verify that the socket is in the listen state
- //
- if ( SOCKET_STATE_LISTENING != pSocket->State ) {
+ if (( NULL != pSockAddr )
+ && ( NULL == pSockAddrLength )) {
DEBUG (( DEBUG_ACCEPT,
- "ERROR - Socket is not listening!\r\n" ));
- Status = EFI_NOT_STARTED;
- pSocket->errno = EOPNOTSUPP;
+ "ERROR - pSockAddr is NULL!\r\n" ));
+ Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = EFAULT;
}
else {
//
- // Determine if a socket is available
+ // Synchronize with the socket layer
//
- if ( 0 == pSocket->FifoDepth ) {
- //
- // No connections available
- // Determine if any ports are available
- //
- if ( NULL == pSocket->pPortList ) {
- //
- // No ports available
- //
- Status = EFI_DEVICE_ERROR;
- pSocket->errno = EINVAL;
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+ //
+ // Verify that the socket is in the listen state
+ //
+ if ( SOCKET_STATE_LISTENING != pSocket->State ) {
+ DEBUG (( DEBUG_ACCEPT,
+ "ERROR - Socket is not listening!\r\n" ));
+ if ( NULL == pSocket->pApi->pfnAccept ) {
//
- // Update the socket state
+ // Socket does not support listen
//
- pSocket->State = SOCKET_STATE_NO_PORTS;
+ pSocket->errno = EOPNOTSUPP;
+ Status = EFI_UNSUPPORTED;
}
else {
//
- // Ports are available
- // No connection requests at this time
+ // Socket supports listen, but not in listen state
//
- Status = EFI_NOT_READY;
- pSocket->errno = EAGAIN;
+ pSocket->errno = EINVAL;
+ Status = EFI_NOT_STARTED;
}
}
else {
-
//
- // Get the remote network address
+ // Determine if a socket is available
//
- pNewSocket = pSocket->pFifoHead;
- ASSERT ( NULL != pNewSocket );
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_ACCEPT,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if ( 0 == pSocket->FifoDepth ) {
//
- // Determine the connection point within the network stack
+ // No connections available
+ // Determine if any ports are available
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_ACCEPT,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- Status = EslTcpAccept4 ( pNewSocket,
- pSockAddr,
- pSockAddrLength );
- break;
-
- /*
- case SOCK_DGRAM:
- Status = UdpAccept4 ( pSocket );
- break;
- */
+ if ( NULL == pSocket->pPortList ) {
+ //
+ // No ports available
+ //
+ Status = EFI_DEVICE_ERROR;
+ pSocket->errno = EINVAL;
+
+ //
+ // Update the socket state
+ //
+ pSocket->State = SOCKET_STATE_NO_PORTS;
}
- break;
- }
- if ( !EFI_ERROR ( Status )) {
- //
- // Remove the new socket from the list
- //
- pSocket->pFifoHead = pNewSocket->pNextConnection;
- if ( NULL == pSocket->pFifoHead ) {
- pSocket->pFifoTail = NULL;
+ else {
+ //
+ // Ports are available
+ // No connection requests at this time
+ //
+ Status = EFI_NOT_READY;
+ pSocket->errno = EAGAIN;
}
+ }
+ else {
//
- // Account for this socket
+ // Attempt to accept the connection and
+ // get the remote network address
//
- pSocket->FifoDepth -= 1;
+ pNewSocket = pSocket->pFifoHead;
+ ASSERT ( NULL != pNewSocket );
+ Status = pSocket->pApi->pfnAccept ( pNewSocket,
+ pSockAddr,
+ pSockAddrLength );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Remove the new socket from the list
+ //
+ pSocket->pFifoHead = pNewSocket->pNextConnection;
+ if ( NULL == pSocket->pFifoHead ) {
+ pSocket->pFifoTail = NULL;
+ }
- //
- // Update the new socket's state
- //
- pNewSocket->State = SOCKET_STATE_CONNECTED;
- pNewSocket->bConfigured = TRUE;
- DEBUG (( DEBUG_ACCEPT,
- "0x%08x: Socket connected\r\n",
- pNewSocket ));
+ //
+ // Account for this socket
+ //
+ pSocket->FifoDepth -= 1;
+
+ //
+ // Update the new socket's state
+ //
+ pNewSocket->State = SOCKET_STATE_CONNECTED;
+ pNewSocket->bConfigured = TRUE;
+ DEBUG (( DEBUG_ACCEPT,
+ "0x%08x: Socket connected\r\n",
+ pNewSocket ));
+ }
}
}
- }
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+ }
}
}
@@ -410,10 +927,9 @@ EslSocketAccept (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
}
}
DBG_EXIT_STATUS ( Status );
@@ -422,9 +938,9 @@ EslSocketAccept (
/**
- Allocate and initialize a DT_SOCKET structure.
+ Allocate and initialize a ESL_SOCKET structure.
- The ::SocketAllocate() function allocates a DT_SOCKET structure
+ This support function allocates an ::ESL_SOCKET structure
and installs a protocol on ChildHandle. If pChildHandle is a
pointer to NULL, then a new handle is created and returned in
pChildHandle. If pChildHandle is not a pointer to NULL, then
@@ -436,11 +952,11 @@ EslSocketAccept (
then the protocol is added to the existing UEFI
handle.
@param [in] DebugFlags Flags for debug messages
- @param [in, out] ppSocket The buffer to receive the DT_SOCKET structure address.
+ @param [in, out] ppSocket The buffer to receive an ::ESL_SOCKET structure address.
@retval EFI_SUCCESS The protocol was added to ChildHandle.
@retval EFI_INVALID_PARAMETER ChildHandle is NULL.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
the child
@retval other The child handle was not created
@@ -450,12 +966,12 @@ EFIAPI
EslSocketAllocate (
IN OUT EFI_HANDLE * pChildHandle,
IN UINTN DebugFlags,
- IN OUT DT_SOCKET ** ppSocket
+ IN OUT ESL_SOCKET ** ppSocket
)
{
UINTN LengthInBytes;
- DT_LAYER * pLayer;
- DT_SOCKET * pSocket;
+ ESL_LAYER * pLayer;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -465,12 +981,8 @@ EslSocketAllocate (
// Create a socket structure
//
LengthInBytes = sizeof ( *pSocket );
- Status = gBS->AllocatePool (
- EfiRuntimeServicesData,
- LengthInBytes,
- (VOID **) &pSocket
- );
- if ( !EFI_ERROR ( Status )) {
+ pSocket = (ESL_SOCKET *) AllocateZeroPool ( LengthInBytes );
+ if ( NULL != pSocket ) {
DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
"0x%08x: Allocate pSocket, %d bytes\r\n",
pSocket,
@@ -479,8 +991,6 @@ EslSocketAllocate (
//
// Initialize the socket protocol
//
- ZeroMem ( pSocket, LengthInBytes );
-
pSocket->Signature = SOCKET_SIGNATURE;
pSocket->SocketProtocol.pfnAccept = EslSocketAccept;
pSocket->SocketProtocol.pfnBind = EslSocketBind;
@@ -494,9 +1004,9 @@ EslSocketAllocate (
pSocket->SocketProtocol.pfnOptionSet = EslSocketOptionSet;
pSocket->SocketProtocol.pfnPoll = EslSocketPoll;
pSocket->SocketProtocol.pfnReceive = EslSocketReceive;
- pSocket->SocketProtocol.pfnSend = EslSocketTransmit;
pSocket->SocketProtocol.pfnShutdown = EslSocketShutdown;
pSocket->SocketProtocol.pfnSocket = EslSocket;
+ pSocket->SocketProtocol.pfnTransmit = EslSocketTransmit;
pSocket->MaxRxBuf = MAX_RX_DATA;
pSocket->MaxTxBuf = MAX_TX_DATA;
@@ -558,9 +1068,7 @@ EslSocketAllocate (
}
}
else {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,
- "ERROR - Failed socket allocation, Status: %r\r\n",
- Status ));
+ Status = EFI_OUT_OF_RESOURCES;
}
//
@@ -574,11 +1082,13 @@ EslSocketAllocate (
/**
Bind a name to a socket.
- The ::SocketBind routine connects a name to a socket on the local machine. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html">POSIX</a>
- documentation for the bind routine is available online for reference.
+ This routine calls the network specific layer to save the network
+ address of the local connection point.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::bind routine calls this routine to connect a name
+ (network address and port) to a socket on the local machine.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] pSockAddr Address of a sockaddr structure that contains the
connection point on the local machine. An IPv4 address
@@ -590,7 +1100,7 @@ EslSocketAllocate (
number from the dynamic range. Specifying a specific
port number causes the network layer to use that port.
- @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.
+ @param [in] SockAddrLength Specifies the length in bytes of the sockaddr structure.
@param [out] pErrno Address to receive the errno value upon completion.
@@ -600,12 +1110,18 @@ EslSocketAllocate (
EFI_STATUS
EslSocketBind (
IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
- IN const struct sockaddr * pSockAddr,
+ IN CONST struct sockaddr * pSockAddr,
IN socklen_t SockAddrLength,
OUT int * pErrno
)
{
- DT_SOCKET * pSocket;
+ EFI_HANDLE ChildHandle;
+ UINT8 * pBuffer;
+ ESL_PORT * pPort;
+ ESL_SERVICE ** ppServiceListHead;
+ ESL_SOCKET * pSocket;
+ ESL_SERVICE * pService;
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -626,91 +1142,130 @@ EslSocketBind (
//
// Validate the structure pointer
//
+ pSocket->errno = 0;
if ( NULL == pSockAddr ) {
DEBUG (( DEBUG_BIND,
"ERROR - pSockAddr is NULL!\r\n" ));
Status = EFI_INVALID_PARAMETER;
pSocket->errno = EFAULT;
}
- else{
+
+ //
+ // Validate the local address length
+ //
+ else if ( SockAddrLength < pSocket->pApi->MinimumAddressLength ) {
+ DEBUG (( DEBUG_BIND,
+ "ERROR - Invalid bind name length: %d\r\n",
+ SockAddrLength ));
+ Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = EINVAL;
+ }
+
+ //
+ // Validate the shutdown state
+ //
+ else if ( pSocket->bRxDisable || pSocket->bTxDisable ) {
+ DEBUG (( DEBUG_BIND,
+ "ERROR - Shutdown has been called on socket 0x%08x\r\n",
+ pSocket ));
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Verify the socket state
+ //
+ else if ( SOCKET_STATE_NOT_CONFIGURED != pSocket->State ) {
+ DEBUG (( DEBUG_BIND,
+ "ERROR - The socket 0x%08x is already configured!\r\n",
+ pSocket ));
+ pSocket->errno = EINVAL;
+ Status = EFI_ALREADY_STARTED;
+ }
+ else {
//
- // Validate the name length
+ // Synchronize with the socket layer
//
- if (( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))
- || ( pSockAddr->sa_len < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))) {
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid bind name length: %d, sa_len: %d\r\n",
- SockAddrLength,
- pSockAddr->sa_len ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
- }
- else {
- //
- // Set the socket address length
- //
- if ( SockAddrLength > pSockAddr->sa_len ) {
- SockAddrLength = pSockAddr->sa_len;
- }
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
- //
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+ //
+ // Assume no ports are available
+ //
+ pSocket->errno = EADDRNOTAVAIL;
+ Status = EFI_INVALID_PARAMETER;
+ //
+ // Walk the list of services
+ //
+ pBuffer = (UINT8 *)&mEslLayer;
+ pBuffer = &pBuffer[ pSocket->pApi->ServiceListOffset ];
+ ppServiceListHead = (ESL_SERVICE **)pBuffer;
+ pService = *ppServiceListHead;
+ while ( NULL != pService ) {
//
- // Validate the local address
+ // Create the port
//
- switch ( pSockAddr->sa_family ) {
- default:
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid bind address family: %d\r\n",
- pSockAddr->sa_family ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
+ pServiceBinding = pService->pServiceBinding;
+ ChildHandle = NULL;
+ Status = pServiceBinding->CreateChild ( pServiceBinding,
+ &ChildHandle );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL,
+ "0x%08x: %s port handle created\r\n",
+ ChildHandle,
+ pService->pSocketBinding->pName ));
- case AF_INET:
//
- // Determine the connection point within the network stack
+ // Open the port
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- Status = EslTcpBind4 ( pSocket,
- pSockAddr,
- SockAddrLength );
- break;
-
- case SOCK_DGRAM:
- Status = EslUdpBind4 ( pSocket,
- pSockAddr,
- SockAddrLength );
- break;
- }
- break;
+ Status = EslSocketPortAllocate ( pSocket,
+ pService,
+ ChildHandle,
+ pSockAddr,
+ TRUE,
+ DEBUG_BIND,
+ &pPort );
+ }
+ else {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL,
+ "ERROR - Failed to open %s port handle, Status: %r\r\n",
+ pService->pSocketBinding->pName,
+ Status ));
}
//
- // Mark this socket as bound if successful
+ // Set the next service
//
- if ( !EFI_ERROR ( Status )) {
- pSocket->State = SOCKET_STATE_BOUND;
+ pService = pService->pNext;
+ }
+
+ //
+ // Verify that at least one network connection was found
+ //
+ if ( NULL == pSocket->pPortList ) {
+ if ( EADDRNOTAVAIL == pSocket->errno ) {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
+ "ERROR - Socket address is not available!\r\n" ));
}
+ if ( EADDRINUSE == pSocket->errno ) {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
+ "ERROR - Socket address is in use!\r\n" ));
+ }
+ Status = EFI_INVALID_PARAMETER;
+ }
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
+ //
+ // Mark this socket as bound if successful
+ //
+ if ( !EFI_ERROR ( Status )) {
+ pSocket->State = SOCKET_STATE_BOUND;
+ pSocket->errno = 0;
}
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
}
}
@@ -721,12 +1276,73 @@ EslSocketBind (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
+ }
+ }
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Test the bind configuration.
+
+ @param [in] pPort Address of the ::ESL_PORT structure.
+ @param [in] ErrnoValue errno value if test fails
+
+ @retval EFI_SUCCESS The connection was successfully established.
+ @retval Others The connection attempt failed.
+
+ **/
+EFI_STATUS
+EslSocketBindTest (
+ IN ESL_PORT * pPort,
+ IN int ErrnoValue
+ )
+{
+ UINT8 * pBuffer;
+ VOID * pConfigData;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Locate the configuration data
+ //
+ pBuffer = (UINT8 *)pPort;
+ pBuffer = &pBuffer [ pPort->pSocket->pApi->ConfigDataOffset ];
+ pConfigData = (VOID *)pBuffer;
+
+ //
+ // Attempt to use this configuration
+ //
+ Status = pPort->pfnConfigure ( pPort->pProtocol.v, pConfigData );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_WARN | DEBUG_BIND,
+ "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",
+ pPort,
+ Status ));
+ pPort->pSocket->errno = ErrnoValue;
+ }
+ else {
+ //
+ // Reset the port
+ //
+ Status = pPort->pfnConfigure ( pPort->pProtocol.v, NULL );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DEBUG_BIND,
+ "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",
+ pPort,
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
}
}
+
+ //
+ // Return the operation status
+ //
DBG_EXIT_STATUS ( Status );
return Status;
}
@@ -735,9 +1351,14 @@ EslSocketBind (
/**
Determine if the socket is closed
- Reverses the operations of the ::SocketAllocate() routine.
+ This routine checks the state of the socket to determine if
+ the network specific layer has completed the close operation.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::close routine polls this routine to determine when the
+ close operation is complete. The close operation needs to
+ reverse the operations of the ::EslSocketAllocate routine.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [out] pErrno Address to receive the errno value upon completion.
@retval EFI_SUCCESS Socket successfully closed
@@ -753,9 +1374,9 @@ EslSocketClosePoll (
)
{
int errno;
- DT_LAYER * pLayer;
- DT_SOCKET * pNextSocket;
- DT_SOCKET * pSocket;
+ ESL_LAYER * pLayer;
+ ESL_SOCKET * pNextSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -868,11 +1489,19 @@ EslSocketClosePoll (
/**
Start the close operation on the socket
- Start closing the socket by closing all of the ports. Upon
- completion, the ::SocketPoll() routine finishes closing the
- socket.
+ This routine calls the network specific layer to initiate the
+ close state machine. This routine then calls the network
+ specific layer to determine if the close state machine has gone
+ to completion. The result from this poll is returned to the
+ caller.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::close routine calls this routine to start the close
+ operation which reverses the operations of the
+ ::EslSocketAllocate routine. The close routine then polls
+ the ::EslSocketClosePoll routine to determine when the
+ socket is closed.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] bCloseNow Boolean to control close behavior
@param [out] pErrno Address to receive the errno value upon completion.
@@ -890,9 +1519,9 @@ EslSocketCloseStart (
)
{
int errno;
- DT_PORT * pNextPort;
- DT_PORT * pPort;
- DT_SOCKET * pSocket;
+ ESL_PORT * pNextPort;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -928,9 +1557,9 @@ EslSocketCloseStart (
// Start closing the ports
//
pNextPort = pPort->pLinkSocket;
- Status = pPort->pfnCloseStart ( pPort,
- bCloseNow,
- DEBUG_CLOSE | DEBUG_LISTEN | DEBUG_CONNECTION );
+ Status = EslSocketPortCloseStart ( pPort,
+ bCloseNow,
+ DEBUG_CLOSE | DEBUG_LISTEN | DEBUG_CONNECTION );
if (( EFI_SUCCESS != Status )
&& ( EFI_NOT_READY != Status )) {
errno = EIO;
@@ -951,8 +1580,8 @@ EslSocketCloseStart (
}
}
else {
- Status = EFI_ALREADY_STARTED;
- errno = EALREADY;
+ Status = EFI_NOT_READY;
+ errno = EAGAIN;
}
//
@@ -974,28 +1603,16 @@ EslSocketCloseStart (
/**
Connect to a remote system via the network.
- The ::SocketConnect routine attempts to establish a connection to a
- socket on the local or remote system using the specified address.
- The POSIX
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html">connect</a>
- documentation is available online.
-
- There are three states associated with a connection:
- <ul>
- <li>Not connected</li>
- <li>Connection in progress</li>
- <li>Connected</li>
- </ul>
- In the "Not connected" state, calls to ::connect start the connection
- processing and update the state to "Connection in progress". During
- the "Connection in progress" state, connect polls for connection completion
- and moves the state to "Connected" after the connection is established.
- Note that these states are only visible when the file descriptor is marked
- with O_NONBLOCK. Also, the POLL_WRITE bit is set when the connection
- completes and may be used by poll or select as an indicator to call
- connect again.
+ This routine calls the network specific layer to establish
+ the remote system address and establish the connection to
+ the remote system.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::connect routine calls this routine to establish a
+ connection with the specified remote system. This routine
+ is designed to be polled by the connect routine for completion
+ of the network connection.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] pSockAddr Network address of the remote system.
@@ -1016,7 +1633,9 @@ EslSocketConnect (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ struct sockaddr_in6 LocalAddress;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -1037,12 +1656,10 @@ EslSocketConnect (
//
// Validate the name length
//
- if (( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))
- || ( pSockAddr->sa_len < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))) {
+ if ( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data ))) {
DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid bind name length: %d, sa_len: %d\r\n",
- SockAddrLength,
- pSockAddr->sa_len ));
+ "ERROR - Invalid bind name length: %d\r\n",
+ SockAddrLength ));
Status = EFI_INVALID_PARAMETER;
pSocket->errno = EINVAL;
}
@@ -1053,13 +1670,6 @@ EslSocketConnect (
pSocket->errno = 0;
//
- // Set the socket address length
- //
- if ( SockAddrLength > pSockAddr->sa_len ) {
- SockAddrLength = pSockAddr->sa_len;
- }
-
- //
// Synchronize with the socket layer
//
RAISE_TPL ( TplPrevious, TPL_SOCKETS );
@@ -1079,112 +1689,111 @@ EslSocketConnect (
case SOCKET_STATE_NOT_CONFIGURED:
case SOCKET_STATE_BOUND:
//
- // Validate the local address
+ // Validate the address length
//
- switch ( pSockAddr->sa_family ) {
- default:
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid bind address family: %d\r\n",
- pSockAddr->sa_family ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if ( SockAddrLength >= pSocket->pApi->MinimumAddressLength ) {
//
- // Determine the connection point within the network stack
+ // Verify the API
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
+ if ( NULL == pSocket->pApi->pfnRemoteAddrSet ) {
//
- // Start the connection processing
+ // Already connected
//
- Status = EslTcpConnectStart4 ( pSocket,
- pSockAddr,
- SockAddrLength );
-
+ pSocket->errno = ENOTSUP;
+ Status = EFI_UNSUPPORTED;
+ }
+ else {
//
- // Set the next state if connecting
+ // Determine if BIND was already called
//
- if ( EFI_NOT_READY == Status ) {
- pSocket->State = SOCKET_STATE_CONNECTING;
+ if ( NULL == pSocket->pPortList ) {
+ //
+ // Allow any local port
+ //
+ ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
+ LocalAddress.sin6_len = (uint8_t)pSocket->pApi->MinimumAddressLength;
+ LocalAddress.sin6_family = pSocket->pApi->AddressFamily;
+ Status = EslSocketBind ( &pSocket->SocketProtocol,
+ (struct sockaddr *)&LocalAddress,
+ LocalAddress.sin6_len,
+ &pSocket->errno );
}
- break;
+ if ( NULL != pSocket->pPortList ) {
+ //
+ // Walk the list of ports
+ //
+ pPort = pSocket->pPortList;
+ while ( NULL != pPort ) {
+ //
+ // Set the remote address
+ //
+ Status = pSocket->pApi->pfnRemoteAddrSet ( pPort,
+ pSockAddr,
+ SockAddrLength );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
- case SOCK_DGRAM:
- Status = EslUdpConnect4 ( pSocket,
- pSockAddr,
- SockAddrLength );
- break;
+ //
+ // Set the next port
+ //
+ pPort = pPort->pLinkSocket;
+ }
+
+ //
+ // Verify the API
+ //
+ if (( !EFI_ERROR ( Status ))
+ && ( NULL != pSocket->pApi->pfnConnectStart )) {
+ //
+ // Initiate the connection with the remote system
+ //
+ Status = pSocket->pApi->pfnConnectStart ( pSocket );
+
+ //
+ // Set the next state if connecting
+ //
+ if ( EFI_NOT_READY == Status ) {
+ pSocket->State = SOCKET_STATE_CONNECTING;
+ }
+ }
+ }
}
- break;
+ }
+ else {
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Invalid address length: %d\r\n",
+ SockAddrLength ));
+ Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = EINVAL;
}
break;
case SOCKET_STATE_CONNECTING:
//
- // Validate the local address
+ // Poll for connection completion
//
- switch ( pSockAddr->sa_family ) {
- default:
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid bind address family: %d\r\n",
- pSockAddr->sa_family ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if ( NULL == pSocket->pApi->pfnConnectPoll ) {
//
- // Determine the connection point within the network stack
+ // Already connected
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- //
- // Determine if the connection processing is completed
- //
- Status = EslTcpConnectPoll4 ( pSocket );
+ pSocket->errno = EISCONN;
+ Status = EFI_ALREADY_STARTED;
+ }
+ else {
+ Status = pSocket->pApi->pfnConnectPoll ( pSocket );
- //
- // Set the next state if connected
- //
- if ( EFI_NOT_READY != Status ) {
- if ( !EFI_ERROR ( Status )) {
- pSocket->State = SOCKET_STATE_CONNECTED;
- }
- else {
- pSocket->State = SOCKET_STATE_BOUND;
- }
+ //
+ // Set the next state if connected
+ //
+ if ( EFI_NOT_READY != Status ) {
+ if ( !EFI_ERROR ( Status )) {
+ pSocket->State = SOCKET_STATE_CONNECTED;
+ }
+ else {
+ pSocket->State = SOCKET_STATE_BOUND;
}
- break;
-
- case SOCK_DGRAM:
- //
- // Already connected
- //
- pSocket->errno = EISCONN;
- Status = EFI_ALREADY_STARTED;
- break;
}
- break;
}
break;
@@ -1211,15 +1820,14 @@ EslSocketConnect (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
//
// Bad socket protocol
//
DEBUG (( DEBUG_ERROR | DEBUG_CONNECT,
"ERROR - pSocketProtocol invalid!\r\n" ));
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
}
}
@@ -1232,213 +1840,96 @@ EslSocketConnect (
/**
- Creates a child handle and installs a protocol.
-
- The CreateChild() function installs a protocol on ChildHandle.
- If pChildHandle is a pointer to NULL, then a new handle is created and returned in pChildHandle.
- If pChildHandle is not a pointer to NULL, then the protocol installs on the existing pChildHandle.
-
- @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
- @param [in] pChildHandle Pointer to the handle of the child to create. If it is NULL,
- then a new handle is created. If it is a pointer to an existing UEFI handle,
- then the protocol is added to the existing UEFI handle.
-
- @retval EFI_SUCCESS The protocol was added to ChildHandle.
- @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
- the child
- @retval other The child handle was not created
+ Copy a fragmented buffer into a destination buffer.
-**/
-EFI_STATUS
-EFIAPI
-EslSocketCreateChild (
- IN EFI_SERVICE_BINDING_PROTOCOL * pThis,
- IN OUT EFI_HANDLE * pChildHandle
- )
-{
- DT_SOCKET * pSocket;
- EFI_STATUS Status;
+ This support routine copies a fragmented buffer to the caller specified buffer.
- DBG_ENTER ( );
+ This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
- //
- // Create a socket structure
- //
- Status = EslSocketAllocate ( pChildHandle,
- DEBUG_SOCKET,
- &pSocket );
+ @param [in] FragmentCount Number of fragments in the table
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
+ @param [in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure
+ @param [in] BufferLength Length of the the buffer
-/**
- Destroys a child handle with a protocol installed on it.
-
- The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
- that was installed by CreateChild() from ChildHandle. If the removed protocol is the
- last protocol on ChildHandle, then ChildHandle is destroyed.
+ @param [in] pBuffer Address of a buffer to receive the data.
- @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
- @param [in] ChildHandle Handle of the child to destroy
+ @param [in] pDataLength Number of received data bytes in the buffer.
- @retval EFI_SUCCESS The protocol was removed from ChildHandle.
- @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
- @retval EFI_INVALID_PARAMETER Child handle is not a valid UEFI Handle.
- @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
- because its services are being used.
- @retval other The child handle was not destroyed
+ @return Returns the address of the next free byte in the buffer.
**/
-EFI_STATUS
-EFIAPI
-EslSocketDestroyChild (
- IN EFI_SERVICE_BINDING_PROTOCOL * pThis,
- IN EFI_HANDLE ChildHandle
+UINT8 *
+EslSocketCopyFragmentedBuffer (
+ IN UINT32 FragmentCount,
+ IN EFI_IP4_FRAGMENT_DATA * pFragmentTable,
+ IN size_t BufferLength,
+ IN UINT8 * pBuffer,
+ OUT size_t * pDataLength
)
{
- DT_LAYER * pLayer;
- DT_SOCKET * pSocket;
- DT_SOCKET * pSocketPrevious;
- EFI_SOCKET_PROTOCOL * pSocketProtocol;
- EFI_STATUS Status;
- EFI_TPL TplPrevious;
+ size_t BytesToCopy;
+ UINT32 Fragment;
+ UINT8 * pBufferEnd;
+ UINT8 * pData;
DBG_ENTER ( );
//
- // Locate the socket control structure
+ // Validate the IP and UDP structures are identical
//
- pLayer = &mEslLayer;
- Status = gBS->OpenProtocol (
- ChildHandle,
- &gEfiSocketProtocolGuid,
- (VOID **)&pSocketProtocol,
- pLayer->ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if ( !EFI_ERROR ( Status )) {
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
-
- //
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+ ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentLength )
+ == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentLength ));
+ ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentBuffer )
+ == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentBuffer ));
+ //
+ // Copy the received data
+ //
+ Fragment = 0;
+ pBufferEnd = &pBuffer [ BufferLength ];
+ while (( pBufferEnd > pBuffer ) && ( FragmentCount > Fragment )) {
//
- // Walk the socket list
+ // Determine the amount of received data
//
- pSocketPrevious = pLayer->pSocketList;
- if ( NULL != pSocketPrevious ) {
- if ( pSocket == pSocketPrevious ) {
- //
- // Remove the socket from the head of the list
- //
- pLayer->pSocketList = pSocket->pNext;
- }
- else {
- //
- // Find the socket in the middle of the list
- //
- while (( NULL != pSocketPrevious )
- && ( pSocket != pSocketPrevious->pNext )) {
- //
- // Set the next socket
- //
- pSocketPrevious = pSocketPrevious->pNext;
- }
- if ( NULL != pSocketPrevious ) {
- //
- // Remove the socket from the middle of the list
- //
- pSocketPrevious = pSocket->pNext;
- }
- }
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_POOL,
- "ERROR - Socket list is empty!\r\n" ));
+ pData = pFragmentTable[Fragment].FragmentBuffer;
+ BytesToCopy = pFragmentTable[Fragment].FragmentLength;
+ if (((size_t)( pBufferEnd - pBuffer )) < BytesToCopy ) {
+ BytesToCopy = pBufferEnd - pBuffer;
}
//
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
-
+ // Move the data into the buffer
//
- // Determine if the socket was found
- //
- if ( NULL != pSocketPrevious ) {
- pSocket->pNext = NULL;
-
- //
- // Remove the socket protocol
- //
- Status = gBS->UninstallMultipleProtocolInterfaces (
- ChildHandle,
- &gEfiSocketProtocolGuid,
- &pSocket->SocketProtocol,
- NULL );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_POOL | DEBUG_INFO,
- "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",
- ChildHandle ));
-
- //
- // Free the socket structure
- //
- Status = gBS->FreePool ( pSocket );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_POOL,
- "0x%08x: Free pSocket, %d bytes\r\n",
- pSocket,
- sizeof ( *pSocket )));
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_POOL,
- "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
- pSocket,
- Status ));
- }
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INFO,
- "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
- ChildHandle,
- Status ));
- }
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_INFO,
- "ERROR - The socket was not in the socket list!\r\n" ));
- Status = EFI_NOT_FOUND;
- }
- }
- else {
- DEBUG (( DEBUG_ERROR,
- "ERROR - Failed to open socket protocol on 0x%08x, Status; %r\r\n",
- ChildHandle,
- Status ));
+ DEBUG (( DEBUG_RX,
+ "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
+ pData,
+ pBuffer,
+ BytesToCopy ));
+ CopyMem ( pBuffer, pData, BytesToCopy );
+ pBuffer += BytesToCopy;
+ Fragment += 1;
}
//
- // Return the operation status
+ // Return the data length and the buffer address
//
- DBG_EXIT_STATUS ( Status );
- return Status;
+ *pDataLength = BufferLength - ( pBufferEnd - pBuffer );
+ DBG_EXIT_HEX ( pBuffer );
+ return pBuffer;
}
/**
Get the local address.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ This routine calls the network specific layer to get the network
+ address of the local host connection point.
+
+ The ::getsockname routine calls this routine to obtain the network
+ address associated with the local host connection point.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [out] pAddress Network address to receive the local system address
@@ -1457,7 +1948,9 @@ EslSocketGetLocalAddress (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ socklen_t LengthInBytes;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -1476,78 +1969,78 @@ EslSocketGetLocalAddress (
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
//
- // Verify the address buffer and length address
+ // Verify the socket state
//
- if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
+ Status = EslSocketIsConfigured ( pSocket );
+ if ( !EFI_ERROR ( Status )) {
//
- // Verify the socket state
+ // Verify the address buffer and length address
//
- if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
- //
- // Synchronize with the socket layer
+ if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
//
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
+ // Verify the socket state
//
- // Validate the local address
- //
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
//
- // Determine the connection point within the network stack
+ // Verify the API
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
+ if ( NULL == pSocket->pApi->pfnLocalAddrGet ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
+ }
+ else {
//
- // Get the local address
+ // Synchronize with the socket layer
//
- Status = EslTcpGetLocalAddress4 ( pSocket,
- pAddress,
- pAddressLength );
- break;
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
- case SOCK_DGRAM:
//
- // Get the local address
+ // Verify that there is just a single connection
//
- Status = EslUdpGetLocalAddress4 ( pSocket,
- pAddress,
- pAddressLength );
- break;
+ pPort = pSocket->pPortList;
+ if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
+ //
+ // Verify the address length
+ //
+ LengthInBytes = pSocket->pApi->AddressLength;
+ if (( LengthInBytes <= *pAddressLength )
+ && ( 255 >= LengthInBytes )) {
+ //
+ // Return the local address and address length
+ //
+ ZeroMem ( pAddress, LengthInBytes );
+ pAddress->sa_len = (uint8_t)LengthInBytes;
+ *pAddressLength = pAddress->sa_len;
+ pSocket->pApi->pfnLocalAddrGet ( pPort, pAddress );
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+ }
+ else {
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+ else {
+ pSocket->errno = ENOTCONN;
+ Status = EFI_NOT_STARTED;
+ }
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
}
- break;
}
-
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
+ else {
+ pSocket->errno = ENOTCONN;
+ Status = EFI_NOT_STARTED;
+ }
}
else {
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
}
}
- else {
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
- }
}
//
@@ -1557,10 +2050,9 @@ EslSocketGetLocalAddress (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
}
}
DBG_EXIT_STATUS ( Status );
@@ -1571,7 +2063,13 @@ EslSocketGetLocalAddress (
/**
Get the peer address.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ This routine calls the network specific layer to get the remote
+ system connection point.
+
+ The ::getpeername routine calls this routine to obtain the network
+ address of the remote connection point.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [out] pAddress Network address to receive the remote system address
@@ -1590,7 +2088,9 @@ EslSocketGetPeerAddress (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ socklen_t LengthInBytes;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -1609,80 +2109,79 @@ EslSocketGetPeerAddress (
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
//
- // Verify the address buffer and length address
+ // Verify the socket state
//
- if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
+ Status = EslSocketIsConfigured ( pSocket );
+ if ( !EFI_ERROR ( Status )) {
//
- // Verify the socket state
+ // Verify the API
//
- if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
- //
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
+ if ( NULL == pSocket->pApi->pfnRemoteAddrGet ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
+ }
+ else {
//
- // Validate the local address
+ // Verify the address buffer and length address
//
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
//
- // Determine the connection point within the network stack
+ // Verify the socket state
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- break;
+ if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
+ //
+ // Synchronize with the socket layer
+ //
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
//
- // Verify the port state
+ // Verify that there is just a single connection
//
- Status = EslTcpGetRemoteAddress4 ( pSocket,
- pAddress,
- pAddressLength );
- break;
+ pPort = pSocket->pPortList;
+ if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
+ //
+ // Verify the address length
+ //
+ LengthInBytes = pSocket->pApi->AddressLength;
+ if ( LengthInBytes <= *pAddressLength ) {
+ //
+ // Return the local address
+ //
+ ZeroMem ( pAddress, LengthInBytes );
+ pAddress->sa_len = (uint8_t)LengthInBytes;
+ *pAddressLength = pAddress->sa_len;
+ pSocket->pApi->pfnRemoteAddrGet ( pPort, pAddress );
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+ }
+ else {
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+ else {
+ pSocket->errno = ENOTCONN;
+ Status = EFI_NOT_STARTED;
+ }
- case SOCK_DGRAM:
//
- // Verify the port state
+ // Release the socket layer synchronization
//
- Status = EslUdpGetRemoteAddress4 ( pSocket,
- pAddress,
- pAddressLength );
- break;
+ RESTORE_TPL ( TplPrevious );
+ }
+ else {
+ pSocket->errno = ENOTCONN;
+ Status = EFI_NOT_STARTED;
}
- break;
}
-
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
- }
- else {
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
+ else {
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ }
}
}
- else {
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
- }
}
-
+
//
// Return the operation status
//
@@ -1690,28 +2189,296 @@ EslSocketGetPeerAddress (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
+ }
+ }
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Free the ESL_IO_MGMT event and structure
+
+ This support routine walks the free list to close the event in
+ the ESL_IO_MGMT structure and remove the structure from the free
+ list.
+
+ See the \ref TransmitEngine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in] ppFreeQueue Address of the free queue head
+ @param [in] DebugFlags Flags for debug messages
+ @param [in] pEventName Zero terminated string containing the event name
+
+ @retval EFI_SUCCESS - The structures were properly initialized
+
+**/
+EFI_STATUS
+EslSocketIoFree (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT ** ppFreeQueue,
+ IN UINTN DebugFlags,
+ IN CHAR8 * pEventName
+ )
+{
+ UINT8 * pBuffer;
+ EFI_EVENT * pEvent;
+ ESL_IO_MGMT * pIo;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Walk the list of IO structures
+ //
+ pSocket = pPort->pSocket;
+ while ( *ppFreeQueue ) {
+ //
+ // Free the event for this structure
+ //
+ pIo = *ppFreeQueue;
+ pBuffer = (UINT8 *)pIo;
+ pBuffer = &pBuffer[ pSocket->TxTokenEventOffset ];
+ pEvent = (EFI_EVENT *)pBuffer;
+ Status = gBS->CloseEvent ( *pEvent );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to close the %a event, Status: %r\r\n",
+ pEventName,
+ Status ));
+ pSocket->errno = ENOMEM;
+ break;
+ }
+ DEBUG (( DebugFlags,
+ "0x%08x: Closed %a event 0x%08x\r\n",
+ pIo,
+ pEventName,
+ *pEvent ));
+
+ //
+ // Remove this structure from the queue
+ //
+ *ppFreeQueue = pIo->pNext;
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Initialize the ESL_IO_MGMT structures
+
+ This support routine initializes the ESL_IO_MGMT structure and
+ places them on to a free list.
+
+ This routine is called by ::EslSocketPortAllocate routines to prepare
+ the transmit engines. See the \ref TransmitEngine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in, out] ppIo Address containing the first structure address. Upon
+ return this buffer contains the next structure address.
+ @param [in] TokenCount Number of structures to initialize
+ @param [in] ppFreeQueue Address of the free queue head
+ @param [in] DebugFlags Flags for debug messages
+ @param [in] pEventName Zero terminated string containing the event name
+ @param [in] pfnCompletion Completion routine address
+
+ @retval EFI_SUCCESS - The structures were properly initialized
+
+**/
+EFI_STATUS
+EslSocketIoInit (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT ** ppIo,
+ IN UINTN TokenCount,
+ IN ESL_IO_MGMT ** ppFreeQueue,
+ IN UINTN DebugFlags,
+ IN CHAR8 * pEventName,
+ IN EFI_EVENT_NOTIFY pfnCompletion
+ )
+{
+ ESL_IO_MGMT * pEnd;
+ EFI_EVENT * pEvent;
+ ESL_IO_MGMT * pIo;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Walk the list of IO structures
+ //
+ pSocket = pPort->pSocket;
+ pIo = *ppIo;
+ pEnd = &pIo [ TokenCount ];
+ while ( pEnd > pIo ) {
+ //
+ // Initialize the IO structure
+ //
+ pIo->pPort = pPort;
+ pIo->pPacket = NULL;
+
+ //
+ // Allocate the event for this structure
+ //
+ pEvent = (EFI_EVENT *)&(((UINT8 *)pIo)[ pSocket->TxTokenEventOffset ]);
+ Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
+ TPL_SOCKETS,
+ (EFI_EVENT_NOTIFY)pfnCompletion,
+ pIo,
+ pEvent );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to create the %a event, Status: %r\r\n",
+ pEventName,
+ Status ));
+ pSocket->errno = ENOMEM;
+ break;
}
+ DEBUG (( DebugFlags,
+ "0x%08x: Created %a event 0x%08x\r\n",
+ pIo,
+ pEventName,
+ *pEvent ));
+
+ //
+ // Add this structure to the queue
+ //
+ pIo->pNext = *ppFreeQueue;
+ *ppFreeQueue = pIo;
+
+ //
+ // Set the next structure
+ //
+ pIo += 1;
}
+
+ //
+ // Save the next structure
+ //
+ *ppIo = pIo;
+
+ //
+ // Return the operation status
+ //
DBG_EXIT_STATUS ( Status );
return Status;
}
/**
+ Determine if the socket is configured
+
+ This support routine is called to determine if the socket if the
+ configuration call was made to the network layer. The following
+ routines call this routine to verify that they may be successful
+ in their operations:
+ <ul>
+ <li>::EslSocketGetLocalAddress</li>
+ <li>::EslSocketGetPeerAddress</li>
+ <li>::EslSocketPoll</li>
+ <li>::EslSocketReceive</li>
+ <li>::EslSocketTransmit</li>
+ </ul>
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
+
+ @retval EFI_SUCCESS - The socket is configured
+
+**/
+EFI_STATUS
+EslSocketIsConfigured (
+ IN ESL_SOCKET * pSocket
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL TplPrevious;
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Verify the socket state
+ //
+ if ( !pSocket->bConfigured ) {
+ DBG_ENTER ( );
+
+ //
+ // Verify the API
+ //
+ if ( NULL == pSocket->pApi->pfnIsConfigured ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
+ }
+ else {
+ //
+ // Synchronize with the socket layer
+ //
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+
+ //
+ // Determine if the socket is configured
+ //
+ Status = pSocket->pApi->pfnIsConfigured ( pSocket );
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+
+ //
+ // Set errno if a failure occurs
+ //
+ if ( EFI_ERROR ( Status )) {
+ pSocket->errno = EADDRNOTAVAIL;
+ }
+ }
+
+ DBG_EXIT_STATUS ( Status );
+ }
+
+ //
+ // Return the configuration status
+ //
+ return Status;
+}
+
+
+/**
Establish the known port to listen for network connections.
- The ::SocketListen routine places the port into a state that enables connection
- attempts. Connections are placed into FIFO order in a queue to be serviced
- by the application. The application calls the ::SocketAccept routine to remove
- the next connection from the queue and get the associated socket. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>
- documentation for the listen routine is available online for reference.
+ This routine calls into the network protocol layer to establish
+ a handler that is called upon connection completion. The handler
+ is responsible for inserting the connection into the FIFO.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::listen routine indirectly calls this routine to place the
+ socket into a state that enables connection attempts. Connections
+ are placed in a FIFO that is serviced by the application. The
+ application calls the ::accept (::EslSocketAccept) routine to
+ remove the next connection from the FIFO and get the associated
+ socket and address.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] Backlog Backlog specifies the maximum FIFO depth for
the connections waiting for the application
@@ -1731,7 +2498,7 @@ EslSocketListen (
OUT int * pErrno
)
{
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_STATUS TempStatus;
EFI_TPL TplPrevious;
@@ -1751,127 +2518,105 @@ EslSocketListen (
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
//
- // Assume success
- //
- pSocket->Status = EFI_SUCCESS;
- pSocket->errno = 0;
-
+ // Verify the API
//
- // Verify that the bind operation was successful
- //
- if ( SOCKET_STATE_BOUND == pSocket->State ) {
+ if ( NULL == pSocket->pApi->pfnListen ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
+ }
+ else {
//
- // Synchronize with the socket layer
+ // Assume success
//
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+ pSocket->Status = EFI_SUCCESS;
+ pSocket->errno = 0;
//
- // Create the event for SocketAccept completion
+ // Verify that the bind operation was successful
//
- Status = gBS->CreateEvent ( 0,
- TplPrevious,
- NULL,
- NULL,
- &pSocket->WaitAccept );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_POOL,
- "0x%08x: Created WaitAccept event\r\n",
- pSocket->WaitAccept ));
+ if ( SOCKET_STATE_BOUND == pSocket->State ) {
//
- // Set the maximum FIFO depth
+ // Synchronize with the socket layer
//
- if ( 0 >= Backlog ) {
- Backlog = MAX_PENDING_CONNECTIONS;
- }
- else {
- if ( SOMAXCONN < Backlog ) {
- Backlog = SOMAXCONN;
- }
- else {
- pSocket->MaxFifoDepth = Backlog;
- }
- }
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
//
- // Validate the local address
+ // Create the event for SocketAccept completion
//
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ Status = gBS->CreateEvent ( 0,
+ TplPrevious,
+ NULL,
+ NULL,
+ &pSocket->WaitAccept );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_POOL,
+ "0x%08x: Created WaitAccept event\r\n",
+ pSocket->WaitAccept ));
//
- // Determine the connection point within the network stack
+ // Set the maximum FIFO depth
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- Status = EslTcpListen4 ( pSocket );
- break;
-
-/*
- case SOCK_DGRAM:
- Status = UdpListen4 ( pSocket );
- break;
-*/
+ if ( 0 >= Backlog ) {
+ Backlog = MAX_PENDING_CONNECTIONS;
+ }
+ else {
+ if ( SOMAXCONN < Backlog ) {
+ Backlog = SOMAXCONN;
+ }
+ else {
+ pSocket->MaxFifoDepth = Backlog;
+ }
}
- break;
- }
- //
- // Place the socket in the listen state if successful
- //
- if ( !EFI_ERROR ( Status )) {
- pSocket->State = SOCKET_STATE_LISTENING;
- }
- else {
//
- // Not waiting for SocketAccept to complete
+ // Initiate the connection attempt listen
+ //
+ Status = pSocket->pApi->pfnListen ( pSocket );
+
+ //
+ // Place the socket in the listen state if successful
//
- TempStatus = gBS->CloseEvent ( pSocket->WaitAccept );
- if ( !EFI_ERROR ( TempStatus )) {
- DEBUG (( DEBUG_POOL,
- "0x%08x: Closed WaitAccept event\r\n",
- pSocket->WaitAccept ));
- pSocket->WaitAccept = NULL;
+ if ( !EFI_ERROR ( Status )) {
+ pSocket->State = SOCKET_STATE_LISTENING;
+ pSocket->bListenCalled = TRUE;
}
else {
- DEBUG (( DEBUG_ERROR | DEBUG_POOL,
- "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
- TempStatus ));
- ASSERT ( EFI_SUCCESS == TempStatus );
+ //
+ // Not waiting for SocketAccept to complete
+ //
+ TempStatus = gBS->CloseEvent ( pSocket->WaitAccept );
+ if ( !EFI_ERROR ( TempStatus )) {
+ DEBUG (( DEBUG_POOL,
+ "0x%08x: Closed WaitAccept event\r\n",
+ pSocket->WaitAccept ));
+ pSocket->WaitAccept = NULL;
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL,
+ "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
+ TempStatus ));
+ ASSERT ( EFI_SUCCESS == TempStatus );
+ }
}
}
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
+ "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
+ Status ));
+ pSocket->errno = ENOMEM;
+ }
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
}
else {
DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
- "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
+ "ERROR - Bind operation must be performed first!\r\n" ));
+ pSocket->errno = ( SOCKET_STATE_NOT_CONFIGURED == pSocket->State ) ? EDESTADDRREQ
+ : EINVAL;
+ Status = EFI_NO_MAPPING;
}
-
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
- "ERROR - Bind operation must be performed first!\r\n" ));
- pSocket->errno = EDESTADDRREQ;
}
}
@@ -1882,10 +2627,9 @@ EslSocketListen (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
}
}
DBG_EXIT_STATUS ( Status );
@@ -1896,11 +2640,13 @@ EslSocketListen (
/**
Get the socket options
- Retrieve the socket options one at a time by name. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html">POSIX</a>
- documentation is available online.
+ This routine handles the socket level options and passes the
+ others to the network specific layer.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::getsockopt routine calls this routine to retrieve the
+ socket options one at a time by name.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] level Option protocol level
@param [in] OptionName Name of the option
@param [out] pOptionValue Buffer to receive the option value
@@ -1925,7 +2671,7 @@ EslSocketOptionGet (
socklen_t LengthInBytes;
socklen_t MaxBytes;
UINT8 * pOptionData;
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -1940,9 +2686,16 @@ EslSocketOptionGet (
// Validate the socket
//
pSocket = NULL;
- if (( NULL != pSocketProtocol )
- && ( NULL != pOptionValue )
- && ( NULL != pOptionLength )) {
+ if ( NULL == pSocketProtocol ) {
+ DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));
+ }
+ else if ( NULL == pOptionValue ) {
+ DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));
+ }
+ else if ( NULL == pOptionLength ) {
+ DEBUG (( DEBUG_OPTION, "ERROR - Option length not specified!\r\n" ));
+ }
+ else {
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
LengthInBytes = 0;
MaxBytes = *pOptionLength;
@@ -1950,20 +2703,70 @@ EslSocketOptionGet (
switch ( level ) {
default:
//
- // Protocol level not supported
+ // See if the protocol will handle the option
//
- errno = ENOTSUP;
- Status = EFI_UNSUPPORTED;
+ if ( NULL != pSocket->pApi->pfnOptionGet ) {
+ if ( pSocket->pApi->DefaultProtocol == level ) {
+ Status = pSocket->pApi->pfnOptionGet ( pSocket,
+ OptionName,
+ &pOptionData,
+ &LengthInBytes );
+ errno = pSocket->errno;
+ break;
+ }
+ else {
+ //
+ // Protocol not supported
+ //
+ DEBUG (( DEBUG_OPTION,
+ "ERROR - The socket does not support this protocol!\r\n" ));
+ }
+ }
+ else {
+ //
+ // Protocol level not supported
+ //
+ DEBUG (( DEBUG_OPTION,
+ "ERROR - %a does not support any options!\r\n",
+ pSocket->pApi->pName ));
+ }
+ errno = ENOPROTOOPT;
+ Status = EFI_INVALID_PARAMETER;
break;
case SOL_SOCKET:
switch ( OptionName ) {
default:
//
- // Option not supported
+ // Socket option not supported
//
- errno = ENOTSUP;
- Status = EFI_UNSUPPORTED;
+ DEBUG (( DEBUG_INFO | DEBUG_OPTION, "ERROR - Invalid socket option!\r\n" ));
+ errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ break;
+
+ case SO_ACCEPTCONN:
+ //
+ // Return the listen flag
+ //
+ pOptionData = (UINT8 *)&pSocket->bListenCalled;
+ LengthInBytes = sizeof ( pSocket->bListenCalled );
+ break;
+
+ case SO_DEBUG:
+ //
+ // Return the debug flags
+ //
+ pOptionData = (UINT8 *)&pSocket->bOobInLine;
+ LengthInBytes = sizeof ( pSocket->bOobInLine );
+ break;
+
+ case SO_OOBINLINE:
+ //
+ // Return the out-of-band inline flag
+ //
+ pOptionData = (UINT8 *)&pSocket->bOobInLine;
+ LengthInBytes = sizeof ( pSocket->bOobInLine );
break;
case SO_RCVTIMEO:
@@ -1976,7 +2779,7 @@ EslSocketOptionGet (
case SO_RCVBUF:
//
- // Return the maximum transmit buffer size
+ // Return the maximum receive buffer size
//
pOptionData = (UINT8 *)&pSocket->MaxRxBuf;
LengthInBytes = sizeof ( pSocket->MaxRxBuf );
@@ -2007,16 +2810,31 @@ EslSocketOptionGet (
*pOptionLength = LengthInBytes;
//
- // Return the option value
+ // Determine if the option is present
//
- if ( NULL != pOptionData ) {
+ if ( 0 != LengthInBytes ) {
//
// Silently truncate the value length
//
if ( LengthInBytes > MaxBytes ) {
+ DEBUG (( DEBUG_OPTION,
+ "INFO - Truncating option from %d to %d bytes\r\n",
+ LengthInBytes,
+ MaxBytes ));
LengthInBytes = MaxBytes;
}
+
+ //
+ // Return the value
+ //
CopyMem ( pOptionValue, pOptionData, LengthInBytes );
+
+ //
+ // Zero fill any remaining space
+ //
+ if ( LengthInBytes < MaxBytes ) {
+ ZeroMem ( &((UINT8 *)pOptionValue)[LengthInBytes], MaxBytes - LengthInBytes );
+ }
errno = 0;
Status = EFI_SUCCESS;
}
@@ -2036,18 +2854,20 @@ EslSocketOptionGet (
/**
Set the socket options
- Adjust the socket options one at a time by name. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html">POSIX</a>
- documentation is available online.
+ This routine handles the socket level options and passes the
+ others to the network specific layer.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::setsockopt routine calls this routine to adjust the socket
+ options one at a time by name.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] level Option protocol level
@param [in] OptionName Name of the option
@param [in] pOptionValue Buffer containing the option value
@param [in] OptionLength Length of the buffer in bytes
@param [out] pErrno Address to receive the errno value upon completion.
- @retval EFI_SUCCESS - Socket data successfully received
+ @retval EFI_SUCCESS - Option successfully set
**/
EFI_STATUS
@@ -2060,10 +2880,11 @@ EslSocketOptionSet (
IN int * pErrno
)
{
+ BOOLEAN bTrueFalse;
int errno;
socklen_t LengthInBytes;
UINT8 * pOptionData;
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -2073,80 +2894,160 @@ EslSocketOptionSet (
//
errno = EINVAL;
Status = EFI_INVALID_PARAMETER;
-
+
//
// Validate the socket
//
pSocket = NULL;
- if (( NULL != pSocketProtocol )
- && ( NULL != pOptionValue )) {
+ if ( NULL == pSocketProtocol ) {
+ DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));
+ }
+ else if ( NULL == pOptionValue ) {
+ DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));
+ }
+ else
+ {
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
- LengthInBytes = 0;
- pOptionData = NULL;
- switch ( level ) {
- default:
- //
- // Protocol level not supported
- //
- errno = ENOTSUP;
- Status = EFI_UNSUPPORTED;
- break;
-
- case SOL_SOCKET:
- switch ( OptionName ) {
+ if ( pSocket->bRxDisable || pSocket->bTxDisable ) {
+ DEBUG (( DEBUG_OPTION, "ERROR - Socket has been shutdown!\r\n" ));
+ }
+ else {
+ LengthInBytes = 0;
+ pOptionData = NULL;
+ switch ( level ) {
default:
//
- // Option not supported
+ // See if the protocol will handle the option
//
- errno = ENOTSUP;
- Status = EFI_UNSUPPORTED;
- break;
-
- case SO_RCVTIMEO:
- //
- // Return the receive timeout
- //
- pOptionData = (UINT8 *)&pSocket->RxTimeout;
- LengthInBytes = sizeof ( pSocket->RxTimeout );
+ if ( NULL != pSocket->pApi->pfnOptionSet ) {
+ if ( pSocket->pApi->DefaultProtocol == level ) {
+ Status = pSocket->pApi->pfnOptionSet ( pSocket,
+ OptionName,
+ pOptionValue,
+ OptionLength );
+ errno = pSocket->errno;
+ break;
+ }
+ else {
+ //
+ // Protocol not supported
+ //
+ DEBUG (( DEBUG_OPTION,
+ "ERROR - The socket does not support this protocol!\r\n" ));
+ }
+ }
+ else {
+ //
+ // Protocol level not supported
+ //
+ DEBUG (( DEBUG_OPTION,
+ "ERROR - %a does not support any options!\r\n",
+ pSocket->pApi->pName ));
+ }
+ errno = ENOPROTOOPT;
+ Status = EFI_INVALID_PARAMETER;
break;
+
+ case SOL_SOCKET:
+ switch ( OptionName ) {
+ default:
+ //
+ // Option not supported
+ //
+ DEBUG (( DEBUG_OPTION,
+ "ERROR - Sockets does not support this option!\r\n" ));
+ errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ break;
- case SO_RCVBUF:
- //
- // Return the maximum transmit buffer size
- //
- pOptionData = (UINT8 *)&pSocket->MaxRxBuf;
- LengthInBytes = sizeof ( pSocket->MaxRxBuf );
- break;
+ case SO_DEBUG:
+ //
+ // Set the debug flags
+ //
+ pOptionData = (UINT8 *)&pSocket->bOobInLine;
+ LengthInBytes = sizeof ( pSocket->bOobInLine );
+ break;
- case SO_SNDBUF:
- //
- // Send buffer size
- //
- //
- // Return the maximum transmit buffer size
- //
- pOptionData = (UINT8 *)&pSocket->MaxTxBuf;
- LengthInBytes = sizeof ( pSocket->MaxTxBuf );
+ case SO_OOBINLINE:
+ pOptionData = (UINT8 *)&pSocket->bOobInLine;
+ LengthInBytes = sizeof ( pSocket->bOobInLine );
+
+ //
+ // Validate the option length
+ //
+ if ( sizeof ( UINT32 ) == OptionLength ) {
+ //
+ // Restrict the input to TRUE or FALSE
+ //
+ bTrueFalse = TRUE;
+ if ( 0 == *(UINT32 *)pOptionValue ) {
+ bTrueFalse = FALSE;
+ }
+ pOptionValue = &bTrueFalse;
+ }
+ else {
+ //
+ // Force an invalid option length error
+ //
+ OptionLength = LengthInBytes - 1;
+ }
+ break;
+
+ case SO_RCVTIMEO:
+ //
+ // Return the receive timeout
+ //
+ pOptionData = (UINT8 *)&pSocket->RxTimeout;
+ LengthInBytes = sizeof ( pSocket->RxTimeout );
+ break;
+
+ case SO_RCVBUF:
+ //
+ // Return the maximum receive buffer size
+ //
+ pOptionData = (UINT8 *)&pSocket->MaxRxBuf;
+ LengthInBytes = sizeof ( pSocket->MaxRxBuf );
+ break;
+
+ case SO_SNDBUF:
+ //
+ // Send buffer size
+ //
+ //
+ // Return the maximum transmit buffer size
+ //
+ pOptionData = (UINT8 *)&pSocket->MaxTxBuf;
+ LengthInBytes = sizeof ( pSocket->MaxTxBuf );
+ break;
+ }
break;
}
- break;
- }
- //
- // Validate the option length
- //
- if ( LengthInBytes <= OptionLength ) {
//
- // Set the option value
+ // Determine if an option was found
//
- if ( NULL != pOptionData ) {
- CopyMem ( pOptionData, pOptionValue, LengthInBytes );
- errno = 0;
- Status = EFI_SUCCESS;
+ if ( 0 != LengthInBytes ) {
+ //
+ // Validate the option length
+ //
+ if ( LengthInBytes <= OptionLength ) {
+ //
+ // Set the option value
+ //
+ CopyMem ( pOptionData, pOptionValue, LengthInBytes );
+ errno = 0;
+ Status = EFI_SUCCESS;
+ }
+ else {
+ DEBUG (( DEBUG_OPTION,
+ "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
+ OptionLength,
+ LengthInBytes ));
+ }
}
}
}
-
+
//
// Return the operation status
//
@@ -2161,8 +3062,13 @@ EslSocketOptionSet (
/**
Allocate a packet for a receive or transmit operation
- @param [in] ppPacket Address to receive the DT_PACKET structure
+ This support routine is called by ::EslSocketRxStart and the
+ network specific TxBuffer routines to get buffer space for the
+ next operation.
+
+ @param [in] ppPacket Address to receive the ::ESL_PACKET structure
@param [in] LengthInBytes Length of the packet structure
+ @param [in] ZeroBytes Length of packet to zero
@param [in] DebugFlags Flags for debug messages
@retval EFI_SUCCESS - The packet was allocated successfully
@@ -2170,12 +3076,13 @@ EslSocketOptionSet (
**/
EFI_STATUS
EslSocketPacketAllocate (
- IN DT_PACKET ** ppPacket,
+ IN ESL_PACKET ** ppPacket,
IN size_t LengthInBytes,
+ IN size_t ZeroBytes,
IN UINTN DebugFlags
)
{
- DT_PACKET * pPacket;
+ ESL_PACKET * pPacket;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -2193,6 +3100,9 @@ EslSocketPacketAllocate (
"0x%08x: Allocate pPacket, %d bytes\r\n",
pPacket,
LengthInBytes ));
+ if ( 0 != ZeroBytes ) {
+ ZeroMem ( &pPacket->Op, ZeroBytes );
+ }
pPacket->PacketSize = LengthInBytes;
}
else {
@@ -2219,7 +3129,12 @@ EslSocketPacketAllocate (
/**
Free a packet used for receive or transmit operation
- @param [in] pPacket Address of the DT_PACKET structure
+ This support routine is called by the network specific Close
+ and TxComplete routines and during error cases in RxComplete
+ and TxBuffer. Note that the network layers typically place
+ receive packets on the ESL_SOCKET::pRxFree list for reuse.
+
+ @param [in] pPacket Address of an ::ESL_PACKET structure
@param [in] DebugFlags Flags for debug messages
@retval EFI_SUCCESS - The packet was allocated successfully
@@ -2227,7 +3142,7 @@ EslSocketPacketAllocate (
**/
EFI_STATUS
EslSocketPacketFree (
- IN DT_PACKET * pPacket,
+ IN ESL_PACKET * pPacket,
IN UINTN DebugFlags
)
{
@@ -2265,10 +3180,14 @@ EslSocketPacketFree (
/**
Poll a socket for pending activity.
- The SocketPoll routine checks a socket for pending activity associated
- with the event mask. Activity is returned in the detected event buffer.
+ This routine builds a detected event mask which is returned to
+ the caller in the buffer provided.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::poll routine calls this routine to determine if the socket
+ needs to be serviced as a result of connection, error, receive or
+ transmit activity.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] Events Events of interest for this socket
@@ -2289,9 +3208,8 @@ EslSocketPoll (
)
{
short DetectedEvents;
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
- EFI_TPL TplPrevious;
short ValidEvents;
DEBUG (( DEBUG_POLL, "Entering SocketPoll\r\n" ));
@@ -2307,60 +3225,7 @@ EslSocketPoll (
//
// Verify the socket state
//
- if ( !pSocket->bConfigured ) {
- //
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
- //
- // Validate the local address
- //
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
- //
- // Determine the connection point within the network stack
- //
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- //
- // Verify the port state
- //
- Status = EslTcpSocketIsConfigured4 ( pSocket );
- break;
-
- case SOCK_DGRAM:
- //
- // Verify the port state
- //
- Status = EslUdpSocketIsConfigured4 ( pSocket );
- break;
- }
- break;
- }
-
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
- }
+ Status = EslSocketIsConfigured ( pSocket );
if ( !EFI_ERROR ( Status )) {
//
// Check for invalid events
@@ -2472,10 +3337,902 @@ EslSocketPoll (
/**
+ Allocate and initialize a ESL_PORT structure.
+
+ This routine initializes an ::ESL_PORT structure for use by
+ the socket. This routine calls a routine via
+ ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
+ specific resources. The resources are released later by the
+ \ref PortCloseStateMachine.
+
+ This support routine is called by:
+ <ul>
+ <li>::EslSocketBind</li>
+ <li>::EslTcp4ListenComplete</li>
+ </ul>
+ to connect the socket with the underlying network adapter
+ to the socket.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
+ @param [in] pService Address of an ::ESL_SERVICE structure.
+ @param [in] ChildHandle Network protocol child handle
+ @param [in] pSockAddr Address of a sockaddr structure that contains the
+ connection point on the local machine. An IPv4 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv4 address restricts the connection to the
+ network stack supporting that address. Specifying zero
+ for the port causes the network layer to assign a port
+ number from the dynamic range. Specifying a specific
+ port number causes the network layer to use that port.
+ @param [in] bBindTest TRUE if EslSocketBindTest should be called
+ @param [in] DebugFlags Flags for debug messages
+ @param [out] ppPort Buffer to receive new ::ESL_PORT structure address
+
+ @retval EFI_SUCCESS - Socket successfully created
+
+ **/
+EFI_STATUS
+EslSocketPortAllocate (
+ IN ESL_SOCKET * pSocket,
+ IN ESL_SERVICE * pService,
+ IN EFI_HANDLE ChildHandle,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest,
+ IN UINTN DebugFlags,
+ OUT ESL_PORT ** ppPort
+ )
+{
+ UINTN LengthInBytes;
+ UINT8 * pBuffer;
+ ESL_IO_MGMT * pIo;
+ ESL_LAYER * pLayer;
+ ESL_PORT * pPort;
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
+ EFI_STATUS Status;
+ EFI_STATUS TempStatus;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Use for/break instead of goto
+ pSocketBinding = pService->pSocketBinding;
+ for ( ; ; ) {
+ //
+ // Allocate a port structure
+ //
+ pLayer = &mEslLayer;
+ LengthInBytes = sizeof ( *pPort )
+ + ESL_STRUCTURE_ALIGNMENT_BYTES
+ + (( pSocketBinding->RxIo
+ + pSocketBinding->TxIoNormal
+ + pSocketBinding->TxIoUrgent )
+ * sizeof ( ESL_IO_MGMT ));
+ pPort = (ESL_PORT *) AllocateZeroPool ( LengthInBytes );
+ if ( NULL == pPort ) {
+ Status = EFI_OUT_OF_RESOURCES;
+ pSocket->errno = ENOMEM;
+ break;
+ }
+ DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
+ "0x%08x: Allocate pPort, %d bytes\r\n",
+ pPort,
+ LengthInBytes ));
+
+ //
+ // Initialize the port
+ //
+ pPort->DebugFlags = DebugFlags;
+ pPort->Handle = ChildHandle;
+ pPort->pService = pService;
+ pPort->pServiceBinding = pService->pServiceBinding;
+ pPort->pSocket = pSocket;
+ pPort->pSocketBinding = pService->pSocketBinding;
+ pPort->Signature = PORT_SIGNATURE;
+
+ //
+ // Open the port protocol
+ //
+ Status = gBS->OpenProtocol ( pPort->Handle,
+ pSocketBinding->pNetworkProtocolGuid,
+ &pPort->pProtocol.v,
+ pLayer->ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
+ pPort->Handle ));
+ pSocket->errno = EEXIST;
+ break;
+ }
+ DEBUG (( DebugFlags,
+ "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
+ pPort->pProtocol.v,
+ pPort->Handle ));
+
+ //
+ // Initialize the port specific resources
+ //
+ Status = pSocket->pApi->pfnPortAllocate ( pPort,
+ DebugFlags );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Set the local address
+ //
+ Status = pSocket->pApi->pfnLocalAddrSet ( pPort, pSockAddr, bBindTest );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Test the address/port configuration
+ //
+ if ( bBindTest ) {
+ Status = EslSocketBindTest ( pPort, pSocket->pApi->BindTestErrno );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+ }
+
+ //
+ // Initialize the receive structures
+ //
+ pBuffer = (UINT8 *)&pPort[ 1 ];
+ pBuffer = &pBuffer[ ESL_STRUCTURE_ALIGNMENT_BYTES ];
+ pBuffer = (UINT8 *)( ESL_STRUCTURE_ALIGNMENT_MASK & (UINTN)pBuffer );
+ pIo = (ESL_IO_MGMT *)pBuffer;
+ if (( 0 != pSocketBinding->RxIo )
+ && ( NULL != pSocket->pApi->pfnRxComplete )) {
+ Status = EslSocketIoInit ( pPort,
+ &pIo,
+ pSocketBinding->RxIo,
+ &pPort->pRxFree,
+ DebugFlags | DEBUG_POOL,
+ "receive",
+ pSocket->pApi->pfnRxComplete );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+ }
+
+ //
+ // Initialize the urgent transmit structures
+ //
+ if (( 0 != pSocketBinding->TxIoUrgent )
+ && ( NULL != pSocket->pApi->pfnTxOobComplete )) {
+ Status = EslSocketIoInit ( pPort,
+ &pIo,
+ pSocketBinding->TxIoUrgent,
+ &pPort->pTxOobFree,
+ DebugFlags | DEBUG_POOL,
+ "urgent transmit",
+ pSocket->pApi->pfnTxOobComplete );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+ }
+
+ //
+ // Initialize the normal transmit structures
+ //
+ if (( 0 != pSocketBinding->TxIoNormal )
+ && ( NULL != pSocket->pApi->pfnTxComplete )) {
+ Status = EslSocketIoInit ( pPort,
+ &pIo,
+ pSocketBinding->TxIoNormal,
+ &pPort->pTxFree,
+ DebugFlags | DEBUG_POOL,
+ "normal transmit",
+ pSocket->pApi->pfnTxComplete );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+ }
+
+ //
+ // Add this port to the socket
+ //
+ pPort->pLinkSocket = pSocket->pPortList;
+ pSocket->pPortList = pPort;
+ DEBUG (( DebugFlags,
+ "0x%08x: Socket adding port: 0x%08x\r\n",
+ pSocket,
+ pPort ));
+
+ //
+ // Add this port to the service
+ //
+ pPort->pLinkService = pService->pPortList;
+ pService->pPortList = pPort;
+
+ //
+ // Return the port
+ //
+ *ppPort = pPort;
+ break;
+ }
+
+ //
+ // Clean up after the error if necessary
+ //
+ if ( EFI_ERROR ( Status )) {
+ if ( NULL != pPort ) {
+ //
+ // Close the port
+ //
+ EslSocketPortClose ( pPort );
+ }
+ else {
+ //
+ // Close the port if necessary
+ //
+ pServiceBinding = pService->pServiceBinding;
+ TempStatus = pServiceBinding->DestroyChild ( pServiceBinding,
+ ChildHandle );
+ if ( !EFI_ERROR ( TempStatus )) {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL,
+ "0x%08x: %s port handle destroyed\r\n",
+ ChildHandle,
+ pSocketBinding->pName ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,
+ "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
+ pSocketBinding->pName,
+ ChildHandle,
+ TempStatus ));
+ ASSERT ( EFI_SUCCESS == TempStatus );
+ }
+ }
+ }
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Close a port.
+
+ This routine releases the resources allocated by ::EslSocketPortAllocate.
+ This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
+ specific resources.
+
+ This routine is called by:
+ <ul>
+ <li>::EslSocketPortAllocate - Port initialization failure</li>
+ <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
+ <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
+ </ul>
+ See the \ref PortCloseStateMachine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @retval EFI_SUCCESS The port is closed
+ @retval other Port close error
+
+**/
+EFI_STATUS
+EslSocketPortClose (
+ IN ESL_PORT * pPort
+ )
+{
+ UINTN DebugFlags;
+ ESL_LAYER * pLayer;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPreviousPort;
+ ESL_SERVICE * pService;
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Locate the port in the socket list
+ //
+ Status = EFI_SUCCESS;
+ pLayer = &mEslLayer;
+ DebugFlags = pPort->DebugFlags;
+ pSocket = pPort->pSocket;
+ pPreviousPort = pSocket->pPortList;
+ if ( pPreviousPort == pPort ) {
+ //
+ // Remove this port from the head of the socket list
+ //
+ pSocket->pPortList = pPort->pLinkSocket;
+ }
+ else {
+ //
+ // Locate the port in the middle of the socket list
+ //
+ while (( NULL != pPreviousPort )
+ && ( pPreviousPort->pLinkSocket != pPort )) {
+ pPreviousPort = pPreviousPort->pLinkSocket;
+ }
+ if ( NULL != pPreviousPort ) {
+ //
+ // Remove the port from the middle of the socket list
+ //
+ pPreviousPort->pLinkSocket = pPort->pLinkSocket;
+ }
+ }
+
+ //
+ // Locate the port in the service list
+ // Note that the port may not be in the service list
+ // if the service has been shutdown.
+ //
+ pService = pPort->pService;
+ if ( NULL != pService ) {
+ pPreviousPort = pService->pPortList;
+ if ( pPreviousPort == pPort ) {
+ //
+ // Remove this port from the head of the service list
+ //
+ pService->pPortList = pPort->pLinkService;
+ }
+ else {
+ //
+ // Locate the port in the middle of the service list
+ //
+ while (( NULL != pPreviousPort )
+ && ( pPreviousPort->pLinkService != pPort )) {
+ pPreviousPort = pPreviousPort->pLinkService;
+ }
+ if ( NULL != pPreviousPort ) {
+ //
+ // Remove the port from the middle of the service list
+ //
+ pPreviousPort->pLinkService = pPort->pLinkService;
+ }
+ }
+ }
+
+ //
+ // Empty the urgent receive queue
+ //
+ while ( NULL != pSocket->pRxOobPacketListHead ) {
+ pPacket = pSocket->pRxOobPacketListHead;
+ pSocket->pRxOobPacketListHead = pPacket->pNext;
+ pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxOobBytes );
+ EslSocketPacketFree ( pPacket, DEBUG_RX );
+ }
+ pSocket->pRxOobPacketListTail = NULL;
+ ASSERT ( 0 == pSocket->RxOobBytes );
+
+ //
+ // Empty the receive queue
+ //
+ while ( NULL != pSocket->pRxPacketListHead ) {
+ pPacket = pSocket->pRxPacketListHead;
+ pSocket->pRxPacketListHead = pPacket->pNext;
+ pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxBytes );
+ EslSocketPacketFree ( pPacket, DEBUG_RX );
+ }
+ pSocket->pRxPacketListTail = NULL;
+ ASSERT ( 0 == pSocket->RxBytes );
+
+ //
+ // Empty the receive free queue
+ //
+ while ( NULL != pSocket->pRxFree ) {
+ pPacket = pSocket->pRxFree;
+ pSocket->pRxFree = pPacket->pNext;
+ EslSocketPacketFree ( pPacket, DEBUG_RX );
+ }
+
+ //
+ // Release the network specific resources
+ //
+ if ( NULL != pSocket->pApi->pfnPortClose ) {
+ Status = pSocket->pApi->pfnPortClose ( pPort );
+ }
+
+ //
+ // Done with the normal transmit events
+ //
+ Status = EslSocketIoFree ( pPort,
+ &pPort->pTxFree,
+ DebugFlags | DEBUG_POOL,
+ "normal transmit" );
+
+ //
+ // Done with the urgent transmit events
+ //
+ Status = EslSocketIoFree ( pPort,
+ &pPort->pTxOobFree,
+ DebugFlags | DEBUG_POOL,
+ "urgent transmit" );
+
+ //
+ // Done with the receive events
+ //
+ Status = EslSocketIoFree ( pPort,
+ &pPort->pRxFree,
+ DebugFlags | DEBUG_POOL,
+ "receive" );
+
+ //
+ // Done with the lower layer network protocol
+ //
+ pSocketBinding = pPort->pSocketBinding;
+ if ( NULL != pPort->pProtocol.v ) {
+ Status = gBS->CloseProtocol ( pPort->Handle,
+ pSocketBinding->pNetworkProtocolGuid,
+ pLayer->ImageHandle,
+ NULL );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags,
+ "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
+ pPort->pProtocol.v,
+ pPort->Handle ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
+ pPort->Handle,
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ }
+
+ //
+ // Done with the network port
+ //
+ pServiceBinding = pPort->pServiceBinding;
+ if ( NULL != pPort->Handle ) {
+ Status = pServiceBinding->DestroyChild ( pServiceBinding,
+ pPort->Handle );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags | DEBUG_POOL,
+ "0x%08x: %s port handle destroyed\r\n",
+ pPort->Handle,
+ pSocketBinding->pName ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
+ "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
+ pSocketBinding->pName,
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ }
+
+ //
+ // Release the port structure
+ //
+ Status = gBS->FreePool ( pPort );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags | DEBUG_POOL,
+ "0x%08x: Free pPort, %d bytes\r\n",
+ pPort,
+ sizeof ( *pPort )));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
+ "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
+ pPort,
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+
+ //
+ // Mark the socket as closed if necessary
+ //
+ if ( NULL == pSocket->pPortList ) {
+ pSocket->State = SOCKET_STATE_CLOSED;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
+ pSocket ));
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Port close state 3
+
+ This routine attempts to complete the port close operation.
+
+ This routine is called by the TCP layer upon completion of
+ the close operation and by ::EslSocketPortCloseTxDone.
+ See the \ref PortCloseStateMachine section.
+
+ @param [in] Event The close completion event
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+**/
+VOID
+EslSocketPortCloseComplete (
+ IN EFI_EVENT Event,
+ IN ESL_PORT * pPort
+ )
+{
+ ESL_IO_MGMT * pIo;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+ VERIFY_AT_TPL ( TPL_SOCKETS );
+
+ //
+ // Update the port state
+ //
+ pPort->State = PORT_STATE_CLOSE_DONE;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
+ pPort ));
+
+ //
+ // Shutdown the receive operation on the port
+ //
+ if ( NULL != pPort->pfnRxCancel ) {
+ pIo = pPort->pRxActive;
+ while ( NULL != pIo ) {
+ EslSocketRxCancel ( pPort, pIo );
+ pIo = pIo->pNext;
+ }
+ }
+
+ //
+ // Determine if the receive operation is pending
+ //
+ Status = EslSocketPortCloseRxDone ( pPort );
+ DBG_EXIT_STATUS ( Status );
+}
+
+
+/**
+ Port close state 4
+
+ This routine determines the state of the receive operations and
+ continues the close operation after the pending receive operations
+ are cancelled.
+
+ This routine is called by
+ <ul>
+ <li>::EslSocketPortCloseComplete</li>
+ <li>::EslSocketPortCloseTxDone</li>
+ <li>::EslSocketRxComplete</li>
+ </ul>
+ to determine the state of the receive operations.
+ See the \ref PortCloseStateMachine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @retval EFI_SUCCESS The port is closed
+ @retval EFI_NOT_READY The port is still closing
+ @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
+ most likely the routine was called already.
+
+**/
+EFI_STATUS
+EslSocketPortCloseRxDone (
+ IN ESL_PORT * pPort
+ )
+{
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Verify that the port is closing
+ //
+ Status = EFI_ALREADY_STARTED;
+ if ( PORT_STATE_CLOSE_DONE == pPort->State ) {
+ //
+ // Determine if the receive operation is pending
+ //
+ Status = EFI_NOT_READY;
+ if ( NULL == pPort->pRxActive ) {
+ //
+ // The receive operation is complete
+ // Update the port state
+ //
+ pPort->State = PORT_STATE_CLOSE_RX_DONE;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
+ pPort ));
+
+ //
+ // Complete the port close operation
+ //
+ Status = EslSocketPortClose ( pPort );
+ }
+ else {
+ DEBUG_CODE_BEGIN ();
+ {
+ ESL_IO_MGMT * pIo;
+ //
+ // Display the outstanding receive operations
+ //
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close: Receive still pending!\r\n",
+ pPort ));
+ pIo = pPort->pRxActive;
+ while ( NULL != pIo ) {
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet pending on network adapter\r\n",
+ pIo->pPacket ));
+ pIo = pIo->pNext;
+ }
+ }
+ DEBUG_CODE_END ( );
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Start the close operation on a port, state 1.
+
+ This routine marks the port as closed and initiates the \ref
+ PortCloseStateMachine. The first step is to allow the \ref
+ TransmitEngine to run down.
+
+ This routine is called by ::EslSocketCloseStart to initiate the socket
+ network specific close operation on the socket.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+ @param [in] bCloseNow Set TRUE to abort active transfers
+ @param [in] DebugFlags Flags for debug messages
+
+ @retval EFI_SUCCESS The port is closed, not normally returned
+ @retval EFI_NOT_READY The port has started the closing process
+ @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
+ most likely the routine was called already.
+
+**/
+EFI_STATUS
+EslSocketPortCloseStart (
+ IN ESL_PORT * pPort,
+ IN BOOLEAN bCloseNow,
+ IN UINTN DebugFlags
+ )
+{
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Mark the port as closing
+ //
+ Status = EFI_ALREADY_STARTED;
+ pSocket = pPort->pSocket;
+ pSocket->errno = EALREADY;
+ if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {
+
+ //
+ // Update the port state
+ //
+ pPort->State = PORT_STATE_CLOSE_STARTED;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
+ pPort ));
+ pPort->bCloseNow = bCloseNow;
+ pPort->DebugFlags = DebugFlags;
+
+ //
+ // Determine if transmits are complete
+ //
+ Status = EslSocketPortCloseTxDone ( pPort );
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Port close state 2
+
+ This routine determines the state of the transmit engine and
+ continue the close operation after the transmission is complete.
+ The next step is to stop the \ref ReceiveEngine.
+ See the \ref PortCloseStateMachine section.
+
+ This routine is called by ::EslSocketPortCloseStart to determine
+ if the transmission is complete.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @retval EFI_SUCCESS The port is closed, not normally returned
+ @retval EFI_NOT_READY The port is still closing
+ @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
+ most likely the routine was called already.
+
+**/
+EFI_STATUS
+EslSocketPortCloseTxDone (
+ IN ESL_PORT * pPort
+ )
+{
+ ESL_IO_MGMT * pIo;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // All transmissions are complete or must be stopped
+ // Mark the port as TX complete
+ //
+ Status = EFI_ALREADY_STARTED;
+ if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {
+ //
+ // Verify that the transmissions are complete
+ //
+ pSocket = pPort->pSocket;
+ if ( pPort->bCloseNow
+ || ( EFI_SUCCESS != pSocket->TxError )
+ || (( NULL == pPort->pTxActive )
+ && ( NULL == pPort->pTxOobActive ))) {
+ //
+ // Update the port state
+ //
+ pPort->State = PORT_STATE_CLOSE_TX_DONE;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
+ pPort ));
+
+ //
+ // Close the port
+ // Skip the close operation if the port is not configured
+ //
+ Status = EFI_SUCCESS;
+ pSocket = pPort->pSocket;
+ if (( pPort->bConfigured )
+ && ( NULL != pSocket->pApi->pfnPortCloseOp )) {
+ //
+ // Start the close operation
+ //
+ Status = pSocket->pApi->pfnPortCloseOp ( pPort );
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close: Close operation still pending!\r\n",
+ pPort ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ else {
+ //
+ // The receive operation is complete
+ // Update the port state
+ //
+ EslSocketPortCloseComplete ( NULL, pPort );
+ }
+ }
+ else {
+ //
+ // Transmissions are still active, exit
+ //
+ Status = EFI_NOT_READY;
+ pSocket->errno = EAGAIN;
+ DEBUG_CODE_BEGIN ( );
+ {
+ ESL_PACKET * pPacket;
+
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close: Transmits are still pending!\r\n",
+ pPort ));
+
+ //
+ // Display the pending urgent transmit packets
+ //
+ pPacket = pSocket->pTxOobPacketListHead;
+ while ( NULL != pPacket ) {
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
+ pPacket,
+ pPacket->PacketSize ));
+ pPacket = pPacket->pNext;
+ }
+
+ pIo = pPort->pTxOobActive;
+ while ( NULL != pIo ) {
+ pPacket = pIo->pPacket;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
+ pPacket,
+ pPacket->PacketSize,
+ pIo ));
+ pIo = pIo->pNext;
+ }
+
+ //
+ // Display the pending normal transmit packets
+ //
+ pPacket = pSocket->pTxPacketListHead;
+ while ( NULL != pPacket ) {
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
+ pPacket,
+ pPacket->PacketSize ));
+ pPacket = pPacket->pNext;
+ }
+
+ pIo = pPort->pTxActive;
+ while ( NULL != pIo ) {
+ pPacket = pIo->pPacket;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
+ pPacket,
+ pPacket->PacketSize,
+ pIo ));
+ pIo = pIo->pNext;
+ }
+ }
+ DEBUG_CODE_END ();
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
Receive data from a network connection.
+ This routine calls the network specific routine to remove the
+ next portion of data from the receive queue and return it to the
+ caller.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::recvfrom routine calls this routine to determine if any data
+ is received from the remote system. Note that the other routines
+ ::recv and ::read are layered on top of ::recvfrom.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] Flags Message control flags
@@ -2506,7 +4263,23 @@ EslSocketReceive (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ union {
+ struct sockaddr_in v4;
+ struct sockaddr_in6 v6;
+ } Addr;
+ socklen_t AddressLength;
+ BOOLEAN bConsumePacket;
+ BOOLEAN bUrgentQueue;
+ size_t DataLength;
+ ESL_PACKET * pNextPacket;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPort;
+ ESL_PACKET ** ppQueueHead;
+ ESL_PACKET ** ppQueueTail;
+ struct sockaddr * pRemoteAddress;
+ size_t * pRxDataBytes;
+ ESL_SOCKET * pSocket;
+ size_t SkipBytes;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -2525,188 +4298,748 @@ EslSocketReceive (
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
//
- // Return the transmit error if necessary
+ // Validate the return address parameters
//
- if ( EFI_SUCCESS != pSocket->TxError ) {
- pSocket->errno = EIO;
- Status = pSocket->TxError;
- pSocket->TxError = EFI_SUCCESS;
- }
- else {
+ if (( NULL == pAddress ) || ( NULL != pAddressLength )) {
//
- // Verify the socket state
+ // Return the transmit error if necessary
//
- if ( !pSocket->bConfigured ) {
- //
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
+ if ( EFI_SUCCESS != pSocket->TxError ) {
+ pSocket->errno = EIO;
+ Status = pSocket->TxError;
+ pSocket->TxError = EFI_SUCCESS;
+ }
+ else {
//
- // Validate the local address
+ // Verify the socket state
//
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ Status = EslSocketIsConfigured ( pSocket );
+ if ( !EFI_ERROR ( Status )) {
//
- // Determine the connection point within the network stack
+ // Validate the buffer length
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
+ if (( NULL == pDataLength )
+ || ( NULL == pBuffer )) {
+ if ( NULL == pDataLength ) {
+ DEBUG (( DEBUG_RX,
+ "ERROR - pDataLength is NULL!\r\n" ));
+ }
+ else {
+ DEBUG (( DEBUG_RX,
+ "ERROR - pBuffer is NULL!\r\n" ));
+ }
Status = EFI_INVALID_PARAMETER;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
+ pSocket->errno = EFAULT;
+ }
+ else {
//
- // Verify the port state
+ // Verify the API
//
- Status = EslTcpSocketIsConfigured4 ( pSocket );
- break;
+ if ( NULL == pSocket->pApi->pfnReceive ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
+ }
+ else {
+ //
+ // Zero the receive address if being returned
+ //
+ pRemoteAddress = NULL;
+ if ( NULL != pAddress ) {
+ pRemoteAddress = (struct sockaddr *)&Addr;
+ ZeroMem ( pRemoteAddress, sizeof ( Addr ));
+ pRemoteAddress->sa_family = pSocket->pApi->AddressFamily;
+ pRemoteAddress->sa_len = (UINT8)pSocket->pApi->AddressLength;
+ }
+
+ //
+ // Synchronize with the socket layer
+ //
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
- case SOCK_DGRAM:
- //
- // Verify the port state
- //
- Status = EslUdpSocketIsConfigured4 ( pSocket );
+ //
+ // Assume failure
+ //
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTCONN;
+
+ //
+ // Verify that the socket is connected
+ //
+ if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
+ //
+ // Locate the port
+ //
+ pPort = pSocket->pPortList;
+ if ( NULL != pPort ) {
+ //
+ // Determine the queue head
+ //
+ bUrgentQueue = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
+ if ( bUrgentQueue ) {
+ ppQueueHead = &pSocket->pRxOobPacketListHead;
+ ppQueueTail = &pSocket->pRxOobPacketListTail;
+ pRxDataBytes = &pSocket->RxOobBytes;
+ }
+ else {
+ ppQueueHead = &pSocket->pRxPacketListHead;
+ ppQueueTail = &pSocket->pRxPacketListTail;
+ pRxDataBytes = &pSocket->RxBytes;
+ }
+
+ //
+ // Determine if there is any data on the queue
+ //
+ *pDataLength = 0;
+ pPacket = *ppQueueHead;
+ if ( NULL != pPacket ) {
+ //
+ // Copy the received data
+ //
+ do {
+ //
+ // Attempt to receive a packet
+ //
+ SkipBytes = 0;
+ bConsumePacket = (BOOLEAN)( 0 == ( Flags & MSG_PEEK ));
+ pBuffer = pSocket->pApi->pfnReceive ( pPort,
+ pPacket,
+ &bConsumePacket,
+ BufferLength,
+ pBuffer,
+ &DataLength,
+ (struct sockaddr *)&Addr,
+ &SkipBytes );
+ *pDataLength += DataLength;
+ BufferLength -= DataLength;
+
+ //
+ // Determine if the data is being read
+ //
+ pNextPacket = pPacket->pNext;
+ if ( bConsumePacket ) {
+ //
+ // All done with this packet
+ // Account for any discarded data
+ //
+ pSocket->pApi->pfnPacketFree ( pPacket, pRxDataBytes );
+ if ( 0 != SkipBytes ) {
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
+ pPort,
+ SkipBytes ));
+ }
+
+ //
+ // Remove this packet from the queue
+ //
+ *ppQueueHead = pPacket->pNext;
+ if ( NULL == *ppQueueHead ) {
+ *ppQueueTail = NULL;
+ }
+
+ //
+ // Move the packet to the free queue
+ //
+ pPacket->pNext = pSocket->pRxFree;
+ pSocket->pRxFree = pPacket;
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port freeing packet 0x%08x\r\n",
+ pPort,
+ pPacket ));
+
+ //
+ // Restart the receive operation if necessary
+ //
+ if (( NULL != pPort->pRxFree )
+ && ( MAX_RX_DATA > pSocket->RxBytes )) {
+ EslSocketRxStart ( pPort );
+ }
+ }
+
+ //
+ // Get the next packet
+ //
+ pPacket = pNextPacket;
+ } while (( SOCK_STREAM == pSocket->Type )
+ && ( NULL != pPacket )
+ && ( 0 < BufferLength ));
+
+ //
+ // Successful operation
+ //
+ Status = EFI_SUCCESS;
+ pSocket->errno = 0;
+ }
+ else {
+ //
+ // The queue is empty
+ // Determine if it is time to return the receive error
+ //
+ if ( EFI_ERROR ( pSocket->RxError )
+ && ( NULL == pSocket->pRxPacketListHead )
+ && ( NULL == pSocket->pRxOobPacketListHead )) {
+ Status = pSocket->RxError;
+ pSocket->RxError = EFI_SUCCESS;
+ switch ( Status ) {
+ default:
+ pSocket->errno = EIO;
+ break;
+
+ case EFI_CONNECTION_FIN:
+ //
+ // Continue to return zero bytes received when the
+ // peer has successfully closed the connection
+ //
+ pSocket->RxError = EFI_CONNECTION_FIN;
+ *pDataLength = 0;
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+ break;
+
+ case EFI_CONNECTION_REFUSED:
+ pSocket->errno = ECONNREFUSED;
+ break;
+
+ case EFI_CONNECTION_RESET:
+ pSocket->errno = ECONNRESET;
+ break;
+
+ case EFI_HOST_UNREACHABLE:
+ pSocket->errno = EHOSTUNREACH;
+ break;
+
+ case EFI_NETWORK_UNREACHABLE:
+ pSocket->errno = ENETUNREACH;
+ break;
+
+ case EFI_PORT_UNREACHABLE:
+ pSocket->errno = EPROTONOSUPPORT;
+ break;
+
+ case EFI_PROTOCOL_UNREACHABLE:
+ pSocket->errno = ENOPROTOOPT;
+ break;
+ }
+ }
+ else {
+ Status = EFI_NOT_READY;
+ pSocket->errno = EAGAIN;
+ }
+ }
+ }
+ }
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+
+ if (( !EFI_ERROR ( Status )) && ( NULL != pAddress )) {
+ //
+ // Return the remote address if requested, truncate if necessary
+ //
+ AddressLength = pRemoteAddress->sa_len;
+ if ( AddressLength > *pAddressLength ) {
+ AddressLength = *pAddressLength;
+ }
+ DEBUG (( DEBUG_RX,
+ "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength, pAddress ));
+ ZeroMem ( pAddress, *pAddressLength );
+ CopyMem ( pAddress, &Addr, AddressLength );
+
+ //
+ // Update the address length
+ //
+ *pAddressLength = pRemoteAddress->sa_len;
+ }
+ }
+ }
+ }
+ }
+
+
+ }
+ else {
+ //
+ // Bad return address pointer and length
+ //
+ Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = EINVAL;
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ if ( NULL != pErrno ) {
+ if ( NULL != pSocket ) {
+ *pErrno = pSocket->errno;
+ }
+ else {
+ Status = EFI_INVALID_PARAMETER;
+ *pErrno = ENOTSOCK;
+ }
+ }
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Cancel the receive operations
+
+ This routine cancels a pending receive operation.
+ See the \ref ReceiveEngine section.
+
+ This routine is called by ::EslSocketShutdown when the socket
+ layer is being shutdown.
+
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+
+ **/
+VOID
+EslSocketRxCancel (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT * pIo
+ )
+{
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Cancel the outstanding receive
+ //
+ Status = pPort->pfnRxCancel ( pPort->pProtocol.v,
+ &pIo->Token );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
+ pIo->pPacket,
+ pPort ));
+ }
+ else {
+ DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
+ pIo->pPacket,
+ pPort,
+ Status ));
+ }
+ DBG_EXIT ( );
+}
+
+
+/**
+ Process the receive completion
+
+ This routine queues the data in FIFO order in either the urgent
+ or normal data queues depending upon the type of data received.
+ See the \ref ReceiveEngine section.
+
+ This routine is called when some data is received by:
+ <ul>
+ <li>::EslIp4RxComplete</li>
+ <li>::EslTcp4RxComplete</li>
+ <li>::EslUdp4RxComplete</li>
+ </ul>
+
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+ @param [in] Status Receive status
+ @param [in] LengthInBytes Length of the receive data
+ @param [in] bUrgent TRUE if urgent data is received and FALSE
+ for normal data.
+
+**/
+VOID
+EslSocketRxComplete (
+ IN ESL_IO_MGMT * pIo,
+ IN EFI_STATUS Status,
+ IN UINTN LengthInBytes,
+ IN BOOLEAN bUrgent
+ )
+{
+ BOOLEAN bUrgentQueue;
+ ESL_IO_MGMT * pIoNext;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPort;
+ ESL_PACKET * pPrevious;
+ ESL_PACKET ** ppQueueHead;
+ ESL_PACKET ** ppQueueTail;
+ size_t * pRxBytes;
+ ESL_SOCKET * pSocket;
+
+ DBG_ENTER ( );
+ VERIFY_AT_TPL ( TPL_SOCKETS );
+
+ //
+ // Locate the active receive packet
+ //
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
+ pSocket = pPort->pSocket;
+
+ //
+ // pPort->pRxActive
+ // |
+ // V
+ // +-------------+ +-------------+ +-------------+
+ // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ // +-------------+ +-------------+ +-------------+
+ //
+ // +-------------+ +-------------+ +-------------+
+ // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ // +-------------+ +-------------+ +-------------+
+ // ^
+ // |
+ // pPort->pRxFree
+ //
+ //
+ // Remove the IO structure from the active list
+ // The following code searches for the entry in the list and does not
+ // assume that the receive operations complete in the order they were
+ // issued to the UEFI network layer.
+ //
+ pIoNext = pPort->pRxActive;
+ while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))
+ {
+ pIoNext = pIoNext->pNext;
+ }
+ ASSERT ( NULL != pIoNext );
+ if ( pIoNext == pIo ) {
+ pPort->pRxActive = pIo->pNext; // Beginning of list
+ }
+ else {
+ pIoNext->pNext = pIo->pNext; // Middle of list
+ }
+
+ //
+ // Free the IO structure
+ //
+ pIo->pNext = pPort->pRxFree;
+ pPort->pRxFree = pIo;
+
+ //
+ // pRxOobPacketListHead pRxOobPacketListTail
+ // | |
+ // V V
+ // +------------+ +------------+ +------------+
+ // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
+ // +------------+ +------------+ +------------+
+ //
+ // +------------+ +------------+ +------------+
+ // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
+ // +------------+ +------------+ +------------+
+ // ^ ^
+ // | |
+ // pRxPacketListHead pRxPacketListTail
+ //
+ //
+ // Determine the queue to use
+ //
+ bUrgentQueue = (BOOLEAN)( bUrgent
+ && pSocket->pApi->bOobSupported
+ && ( !pSocket->bOobInLine ));
+ if ( bUrgentQueue ) {
+ ppQueueHead = &pSocket->pRxOobPacketListHead;
+ ppQueueTail = &pSocket->pRxOobPacketListTail;
+ pRxBytes = &pSocket->RxOobBytes;
+ }
+ else {
+ ppQueueHead = &pSocket->pRxPacketListHead;
+ ppQueueTail = &pSocket->pRxPacketListTail;
+ pRxBytes = &pSocket->RxBytes;
+ }
+
+ //
+ // Determine if this receive was successful
+ //
+ if (( !EFI_ERROR ( Status ))
+ && ( PORT_STATE_CLOSE_STARTED > pPort->State )
+ && ( !pSocket->bRxDisable )) {
+ //
+ // Account for the received data
+ //
+ *pRxBytes += LengthInBytes;
+
+ //
+ // Log the received data
+ //
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
+ pPacket,
+ bUrgentQueue ? L"urgent" : L"normal",
+ pPort,
+ LengthInBytes,
+ bUrgent ? L"urgent" : L"normal" ));
+
+ //
+ // Add the packet to the list tail.
+ //
+ pPacket->pNext = NULL;
+ pPrevious = *ppQueueTail;
+ if ( NULL == pPrevious ) {
+ *ppQueueHead = pPacket;
+ }
+ else {
+ pPrevious->pNext = pPacket;
+ }
+ *ppQueueTail = pPacket;
+
+ //
+ // Attempt to restart this receive operation
+ //
+ if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
+ EslSocketRxStart ( pPort );
+ }
+ else {
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
+ pPort,
+ pSocket->RxBytes ));
+ }
+ }
+ else {
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
+ pPort,
+ pPacket,
+ Status ));
+ }
+
+ //
+ // Account for the receive bytes and release the driver's buffer
+ //
+ if ( !EFI_ERROR ( Status )) {
+ *pRxBytes += LengthInBytes;
+ pSocket->pApi->pfnPacketFree ( pPacket, pRxBytes );
+ }
+
+ //
+ // Receive error, free the packet save the error
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_RX );
+ if ( !EFI_ERROR ( pSocket->RxError )) {
+ pSocket->RxError = Status;
+ }
+
+ //
+ // Update the port state
+ //
+ if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
+ if ( PORT_STATE_CLOSE_DONE == pPort->State ) {
+ EslSocketPortCloseRxDone ( pPort );
+ }
+ }
+ else {
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
+ pPort,
+ Status ));
+ pPort->State = PORT_STATE_RX_ERROR;
+ }
+ }
+ }
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Start a receive operation
+
+ This routine posts a receive buffer to the network adapter.
+ See the \ref ReceiveEngine section.
+
+ This support routine is called by:
+ <ul>
+ <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
+ <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
+ <li>::EslIp4SocketIsConfigured to start the recevie engine for the new socket.</li>
+ <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
+ <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
+ <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
+ <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
+ <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
+ <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
+ </ul>
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ **/
+VOID
+EslSocketRxStart (
+ IN ESL_PORT * pPort
+ )
+{
+ UINT8 * pBuffer;
+ ESL_IO_MGMT * pIo;
+ ESL_PACKET * pPacket;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Determine if a receive is already pending
+ //
+ Status = EFI_SUCCESS;
+ pPacket = NULL;
+ pSocket = pPort->pSocket;
+ if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
+ if (( NULL != pPort->pRxFree )
+ && ( !pSocket->bRxDisable )
+ && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
+ //
+ // Start all of the pending receive operations
+ //
+ while ( NULL != pPort->pRxFree ) {
+ //
+ // Determine if there are any free packets
+ //
+ pPacket = pSocket->pRxFree;
+ if ( NULL != pPacket ) {
+ //
+ // Remove this packet from the free list
+ //
+ pSocket->pRxFree = pPacket->pNext;
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port removed packet 0x%08x from free list\r\n",
+ pPort,
+ pPacket ));
+ }
+ else {
+ //
+ // Allocate a packet structure
+ //
+ Status = EslSocketPacketAllocate ( &pPacket,
+ pSocket->pApi->RxPacketBytes,
+ pSocket->pApi->RxZeroBytes,
+ DEBUG_RX );
+ if ( EFI_ERROR ( Status )) {
+ pPacket = NULL;
+ DEBUG (( DEBUG_ERROR | DEBUG_RX,
+ "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
+ pPort,
+ Status ));
break;
}
- break;
}
//
- // Release the socket layer synchronization
+ // Connect the IO and packet structures
//
- RESTORE_TPL ( TplPrevious );
+ pIo = pPort->pRxFree;
+ pIo->pPacket = pPacket;
//
- // Set errno if a failure occurs
+ // Eliminate the need for IP4 and UDP4 specific routines by
+ // clearing the RX data pointer here.
//
- if ( EFI_ERROR ( Status )) {
- pSocket->errno = EADDRNOTAVAIL;
- }
- }
- if ( !EFI_ERROR ( Status )) {
+ // No driver buffer for this packet
//
- // Validate the buffer length
+ // +--------------------+
+ // | ESL_IO_MGMT |
+ // | |
+ // | +---------------+
+ // | | Token |
+ // | | RxData --> NULL
+ // +----+---------------+
//
- if (( NULL == pDataLength )
- && ( 0 > pDataLength )
- && ( NULL == pBuffer )) {
- if ( NULL == pDataLength ) {
- DEBUG (( DEBUG_RX,
- "ERROR - pDataLength is NULL!\r\n" ));
- }
- else if ( NULL == pBuffer ) {
- DEBUG (( DEBUG_RX,
- "ERROR - pBuffer is NULL!\r\n" ));
- }
- else {
- DEBUG (( DEBUG_RX,
- "ERROR - Data length < 0!\r\n" ));
- }
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EFAULT;
+ pBuffer = (UINT8 *)pIo;
+ pBuffer = &pBuffer[ pSocket->pApi->RxBufferOffset ];
+ *(VOID **)pBuffer = NULL;
+
+ //
+ // Network specific receive packet initialization
+ //
+ if ( NULL != pSocket->pApi->pfnRxStart ) {
+ pSocket->pApi->pfnRxStart ( pPort, pIo );
}
- else{
+
+ //
+ // Start the receive on the packet
+ //
+ Status = pPort->pfnRxStart ( pPort->pProtocol.v, &pIo->Token );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Packet receive pending on port 0x%08x\r\n",
+ pPacket,
+ pPort ));
//
- // Synchronize with the socket layer
+ // Allocate the receive control structure
//
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
+ pPort->pRxFree = pIo->pNext;
+
//
- // Validate the local address
+ // Mark this receive as pending
//
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ pIo->pNext = pPort->pRxActive;
+ pPort->pRxActive = pIo;
+
+ }
+ else {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
+ pPort,
+ Status ));
+ if ( !EFI_ERROR ( pSocket->RxError )) {
//
- // Determine the connection point within the network stack
+ // Save the error status
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- Status = EslTcpReceive4 ( pSocket,
- Flags,
- BufferLength,
- pBuffer,
- pDataLength,
- pAddress,
- pAddressLength );
- break;
-
- case SOCK_DGRAM:
- Status = EslUdpReceive4 ( pSocket,
- Flags,
- BufferLength,
- pBuffer,
- pDataLength,
- pAddress,
- pAddressLength);
- break;
- }
- break;
+ pSocket->RxError = Status;
}
//
- // Release the socket layer synchronization
+ // Free the packet
//
- RESTORE_TPL ( TplPrevious );
+ pIo->pPacket = NULL;
+ pPacket->pNext = pSocket->pRxFree;
+ pSocket->pRxFree = pPacket;
+ break;
}
}
}
- }
-
- //
- // Return the operation status
- //
- if ( NULL != pErrno ) {
- if ( NULL != pSocket ) {
- *pErrno = pSocket->errno;
- }
- else
- {
- Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ else {
+ if ( NULL == pPort->pRxFree ) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
+ pPort));
+ }
+ if ( pSocket->bRxDisable ) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Port, receive disabled!\r\n",
+ pPort ));
+ }
+ if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Port, is closing!\r\n",
+ pPort ));
+ }
}
}
- DBG_EXIT_STATUS ( Status );
- return Status;
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_RX,
+ "ERROR - Previous receive error, Status: %r\r\n",
+ pPort->pSocket->RxError ));
+ }
+
+ DBG_EXIT ( );
}
/**
Shutdown the socket receive and transmit operations
- The SocketShutdown routine stops the socket receive and transmit
- operations.
+ This routine sets a flag to stop future transmissions and calls
+ the network specific layer to cancel the pending receive operation.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::shutdown routine calls this routine to stop receive and transmit
+ operations on the socket.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] How Which operations to stop
@@ -2722,7 +5055,9 @@ EslSocketShutdown (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ ESL_IO_MGMT * pIo;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -2768,47 +5103,29 @@ EslSocketShutdown (
}
//
- // Validate the local address
+ // Cancel the pending receive operations
//
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if ( pSocket->bRxDisable ) {
//
- // Determine the connection point within the network stack
+ // Walk the list of ports
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
+ pPort = pSocket->pPortList;
+ while ( NULL != pPort ) {
//
- // Cancel the pending receive operation
+ // Walk the list of active receive operations
//
- Status = EslTcpRxCancel4 ( pSocket );
- break;
-
- case SOCK_DGRAM:
+ pIo = pPort->pRxActive;
+ while ( NULL != pIo ) {
+ EslSocketRxCancel ( pPort, pIo );
+ }
+
//
- // Cancel the pending receive operation
+ // Set the next port
//
- Status = EslUdpRxCancel4 ( pSocket );
- break;
+ pPort = pPort->pLinkSocket;
}
- break;
}
-
+
//
// Release the socket layer synchronization
//
@@ -2816,18 +5133,18 @@ EslSocketShutdown (
}
else {
//
- // The socket is not connected
+ // Invalid How value
//
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
}
}
else {
//
- // Invalid How value
+ // The socket is not connected
//
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = ENOTCONN;
+ Status = EFI_NOT_STARTED;
}
}
@@ -2838,10 +5155,9 @@ EslSocketShutdown (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
}
}
DBG_EXIT_STATUS ( Status );
@@ -2852,10 +5168,17 @@ EslSocketShutdown (
/**
Send data using a network connection.
- The SocketTransmit routine queues the data for transmission to the
- remote network connection.
+ This routine calls the network specific layer to queue the data
+ for transmission. Eventually the buffer will reach the head of
+ the queue and will get transmitted over the network by the
+ \ref TransmitEngine. For datagram
+ sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
+ the data reaches the application running on the remote system.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::sendto routine calls this routine to send data to the remote
+ system. Note that ::send and ::write are layered on top of ::sendto.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] Flags Message control flags
@@ -2886,7 +5209,7 @@ EslSocketTransmit (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -2916,66 +5239,7 @@ EslSocketTransmit (
//
// Verify the socket state
//
- if ( !pSocket->bConfigured ) {
- //
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
- //
- // Validate the local address
- //
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
- //
- // Determine the connection point within the network stack
- //
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- //
- // Verify the port state
- //
- Status = EslTcpSocketIsConfigured4 ( pSocket );
- break;
-
- case SOCK_DGRAM:
- //
- // Verify the port state
- //
- Status = EslUdpSocketIsConfigured4 ( pSocket );
- break;
- }
- break;
- }
-
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
-
- //
- // Set errno if a failure occurs
- //
- if ( EFI_ERROR ( Status )) {
- pSocket->errno = EADDRNOTAVAIL;
- }
- }
+ Status = EslSocketIsConfigured ( pSocket );
if ( !EFI_ERROR ( Status )) {
//
// Verify that transmit is still allowed
@@ -3015,61 +5279,34 @@ EslSocketTransmit (
}
else {
//
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
- //
- // Validate the local address
+ // Verify the API
//
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if ( NULL == pSocket->pApi->pfnTransmit ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
+ }
+ else {
//
- // Determine the connection point within the network stack
+ // Synchronize with the socket layer
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- Status = EslTcpTxBuffer4 ( pSocket,
- Flags,
- BufferLength,
- pBuffer,
- pDataLength );
- break;
+ //
+ // Attempt to buffer the packet for transmission
+ //
+ Status = pSocket->pApi->pfnTransmit ( pSocket,
+ Flags,
+ BufferLength,
+ pBuffer,
+ pDataLength,
+ pAddress,
+ AddressLength );
- case SOCK_DGRAM:
- Status = EslUdpTxBuffer4 ( pSocket,
- Flags,
- BufferLength,
- pBuffer,
- pDataLength,
- pAddress,
- AddressLength );
- break;
- }
- break;
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
}
-
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
}
}
}
@@ -3091,10 +5328,9 @@ EslSocketTransmit (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
}
}
DBG_EXIT_STATUS ( Status );
@@ -3103,9 +5339,325 @@ EslSocketTransmit (
/**
- Socket layer's service binding protocol delcaration.
-**/
-EFI_SERVICE_BINDING_PROTOCOL mEfiServiceBinding = {
- EslSocketCreateChild,
- EslSocketDestroyChild
-};
+ Complete the transmit operation
+
+ This support routine handles the transmit completion processing for
+ the various network layers. It frees the ::ESL_IO_MGMT structure
+ and and frees packet resources by calling ::EslSocketPacketFree.
+ Transmit errors are logged in ESL_SOCKET::TxError.
+ See the \ref TransmitEngine section.
+
+ This routine is called by:
+ <ul>
+ <li>::EslIp4TxComplete</li>
+ <li>::EslTcp4TxComplete</li>
+ <li>::EslTcp4TxOobComplete</li>
+ <li>::EslUdp4TxComplete</li>
+ </ul>
+
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+ @param [in] LengthInBytes Length of the data in bytes
+ @param [in] Status Transmit operation status
+ @param [in] pQueueType Zero terminated string describing queue type
+ @param [in] ppQueueHead Transmit queue head address
+ @param [in] ppQueueTail Transmit queue tail address
+ @param [in] ppActive Active transmit queue address
+ @param [in] ppFree Free transmit queue address
+
+ **/
+VOID
+EslSocketTxComplete (
+ IN ESL_IO_MGMT * pIo,
+ IN UINT32 LengthInBytes,
+ IN EFI_STATUS Status,
+ IN CONST CHAR8 * pQueueType,
+ IN ESL_PACKET ** ppQueueHead,
+ IN ESL_PACKET ** ppQueueTail,
+ IN ESL_IO_MGMT ** ppActive,
+ IN ESL_IO_MGMT ** ppFree
+ )
+{
+ ESL_PACKET * pCurrentPacket;
+ ESL_IO_MGMT * pIoNext;
+ ESL_PACKET * pNextPacket;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
+
+ DBG_ENTER ( );
+ VERIFY_AT_TPL ( TPL_SOCKETS );
+
+ //
+ // Locate the active transmit packet
+ //
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
+ pSocket = pPort->pSocket;
+
+ //
+ // No more packet
+ //
+ pIo->pPacket = NULL;
+
+ //
+ // Remove the IO structure from the active list
+ //
+ pIoNext = *ppActive;
+ while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))
+ {
+ pIoNext = pIoNext->pNext;
+ }
+ ASSERT ( NULL != pIoNext );
+ if ( pIoNext == pIo ) {
+ *ppActive = pIo->pNext; // Beginning of list
+ }
+ else {
+ pIoNext->pNext = pIo->pNext; // Middle of list
+ }
+
+ //
+ // Free the IO structure
+ //
+ pIo->pNext = *ppFree;
+ *ppFree = pIo;
+
+ //
+ // Display the results
+ //
+ DEBUG (( DEBUG_TX | DEBUG_INFO,
+ "0x%08x: pIo Released\r\n",
+ pIo ));
+
+ //
+ // Save any transmit error
+ //
+ if ( EFI_ERROR ( Status )) {
+ if ( !EFI_ERROR ( pSocket->TxError )) {
+ pSocket->TxError = Status;
+ }
+ DEBUG (( DEBUG_TX | DEBUG_INFO,
+ "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
+ pQueueType,
+ pPacket,
+ Status ));
+
+ //
+ // Empty the normal transmit list
+ //
+ pCurrentPacket = pPacket;
+ pNextPacket = *ppQueueHead;
+ while ( NULL != pNextPacket ) {
+ pPacket = pNextPacket;
+ pNextPacket = pPacket->pNext;
+ EslSocketPacketFree ( pPacket, DEBUG_TX );
+ }
+ *ppQueueHead = NULL;
+ *ppQueueTail = NULL;
+ pPacket = pCurrentPacket;
+ }
+ else {
+ DEBUG (( DEBUG_TX | DEBUG_INFO,
+ "0x%08x: %apacket transmitted %d bytes successfully\r\n",
+ pPacket,
+ pQueueType,
+ LengthInBytes ));
+
+ //
+ // Verify the transmit engine is still running
+ //
+ if ( !pPort->bCloseNow ) {
+ //
+ // Start the next packet transmission
+ //
+ EslSocketTxStart ( pPort,
+ ppQueueHead,
+ ppQueueTail,
+ ppActive,
+ ppFree );
+ }
+ }
+
+ //
+ // Release this packet
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_TX );
+
+ //
+ // Finish the close operation if necessary
+ //
+ if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
+ //
+ // Indicate that the transmit is complete
+ //
+ EslSocketPortCloseTxDone ( pPort );
+ }
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Transmit data using a network connection.
+
+ This support routine starts a transmit operation on the
+ underlying network layer.
+
+ The network specific code calls this routine to start a
+ transmit operation. See the \ref TransmitEngine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in] ppQueueHead Transmit queue head address
+ @param [in] ppQueueTail Transmit queue tail address
+ @param [in] ppActive Active transmit queue address
+ @param [in] ppFree Free transmit queue address
+
+ **/
+VOID
+EslSocketTxStart (
+ IN ESL_PORT * pPort,
+ IN ESL_PACKET ** ppQueueHead,
+ IN ESL_PACKET ** ppQueueTail,
+ IN ESL_IO_MGMT ** ppActive,
+ IN ESL_IO_MGMT ** ppFree
+ )
+{
+ UINT8 * pBuffer;
+ ESL_IO_MGMT * pIo;
+ ESL_PACKET * pNextPacket;
+ ESL_PACKET * pPacket;
+ VOID ** ppTokenData;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Get the packet from the queue head
+ //
+ pPacket = *ppQueueHead;
+ pIo = *ppFree;
+ if (( NULL != pPacket ) && ( NULL != pIo )) {
+ pSocket = pPort->pSocket;
+ //
+ // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
+ // |
+ // V
+ // +------------+ +------------+ +------------+
+ // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
+ // +------------+ +------------+ +------------+
+ // ^
+ // |
+ // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
+ //
+ //
+ // Remove the packet from the queue
+ //
+ pNextPacket = pPacket->pNext;
+ *ppQueueHead = pNextPacket;
+ if ( NULL == pNextPacket ) {
+ *ppQueueTail = NULL;
+ }
+ pPacket->pNext = NULL;
+
+ //
+ // Eliminate the need for IP4 and UDP4 specific routines by
+ // connecting the token with the TX data control structure here.
+ //
+ // +--------------------+ +--------------------+
+ // | ESL_IO_MGMT | | ESL_PACKET |
+ // | | | |
+ // | +---------------+ +----------------+ |
+ // | | Token | | Buffer Length | |
+ // | | TxData --> | Buffer Address | |
+ // | | | +----------------+---+
+ // | | Event | | Data Buffer |
+ // +----+---------------+ | |
+ // +--------------------+
+ //
+ // Compute the address of the TxData pointer in the token
+ //
+ pBuffer = (UINT8 *)&pIo->Token;
+ pBuffer = &pBuffer[ pSocket->TxTokenOffset ];
+ ppTokenData = (VOID **)pBuffer;
+
+ //
+ // Compute the address of the TX data control structure in the packet
+ //
+ // * EFI_IP4_TRANSMIT_DATA
+ // * EFI_TCP4_TRANSMIT_DATA
+ // * EFI_UDP4_TRANSMIT_DATA
+ //
+ pBuffer = (UINT8 *)pPacket;
+ pBuffer = &pBuffer[ pSocket->TxPacketOffset ];
+
+ //
+ // Connect the token to the transmit data control structure
+ //
+ *ppTokenData = (VOID **)pBuffer;
+
+ //
+ // Display the results
+ //
+ DEBUG (( DEBUG_TX | DEBUG_INFO,
+ "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
+ pIo,
+ pPacket ));
+
+ //
+ // Start the transmit operation
+ //
+ Status = pPort->pfnTxStart ( pPort->pProtocol.v,
+ &pIo->Token );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Connect the structures
+ //
+ pIo->pPacket = pPacket;
+
+ //
+ // +-------------+ +-------------+ +-------------+
+ // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ // +-------------+ +-------------+ +-------------+
+ // ^
+ // |
+ // *ppFree: pPort->pTxFree or pTxOobFree
+ //
+ //
+ // Remove the IO structure from the queue
+ //
+ *ppFree = pIo->pNext;
+
+ //
+ // *ppActive: pPort->pTxActive or pTxOobActive
+ // |
+ // V
+ // +-------------+ +-------------+ +-------------+
+ // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ // +-------------+ +-------------+ +-------------+
+ //
+ //
+ // Mark this packet as active
+ //
+ pIo->pPacket = pPacket;
+ pIo->pNext = *ppActive;
+ *ppActive = pIo;
+ }
+ else {
+ if ( EFI_SUCCESS == pSocket->TxError ) {
+ pSocket->TxError = Status;
+ }
+
+ //
+ // Discard the transmit buffer
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_TX );
+ }
+ }
+
+ DBG_EXIT ( );
+}
diff --git a/StdLib/EfiSocketLib/Socket.h b/StdLib/EfiSocketLib/Socket.h
index 42377eb29c..25133e6f89 100644
--- a/StdLib/EfiSocketLib/Socket.h
+++ b/StdLib/EfiSocketLib/Socket.h
@@ -30,27 +30,26 @@
#define DEBUG_TX 0x00400000 ///< Display transmit messages
#define DEBUG_CLOSE 0x00200000 ///< Display close messages
#define DEBUG_CONNECT 0x00100000 ///< Display connect messages
+#define DEBUG_OPTION 0x00080000 ///< Display option messages
#define MAX_PENDING_CONNECTIONS 1 ///< Maximum connection FIFO depth
#define MAX_RX_DATA 65536 ///< Maximum receive data size
-#define MAX_TX_DATA ( MAX_RX_DATA * 2 )
+#define MAX_TX_DATA ( MAX_RX_DATA * 2 ) ///< Maximum buffered transmit data in bytes
#define RX_PACKET_DATA 16384 ///< Maximum number of bytes in a RX packet
+#define MAX_UDP_RETRANSMIT 16 ///< UDP retransmit attempts to handle address not mapped
-#define LAYER_SIGNATURE SIGNATURE_32('S','k','t','L') ///< DT_LAYER memory signature
-#define SERVICE_SIGNATURE SIGNATURE_32('S','k','t','S') ///< DT_SERVICE memory signature
-#define SOCKET_SIGNATURE SIGNATURE_32('S','c','k','t') ///< DT_SOCKET memory signature
-#define PORT_SIGNATURE SIGNATURE_32('P','o','r','t') ///< DT_PORT memory signature
+#define ESL_STRUCTURE_ALIGNMENT_BYTES 15 ///< Number of bytes for structure alignment
+#define ESL_STRUCTURE_ALIGNMENT_MASK ( ~ESL_STRUCTURE_ALIGNMENT_BYTES ) ///< Mask to align structures
+
+#define LAYER_SIGNATURE SIGNATURE_32 ('S','k','t','L') ///< ESL_LAYER memory signature
+#define SERVICE_SIGNATURE SIGNATURE_32 ('S','k','t','S') ///< ESL_SERVICE memory signature
+#define SOCKET_SIGNATURE SIGNATURE_32 ('S','c','k','t') ///< ESL_SOCKET memory signature
+#define PORT_SIGNATURE SIGNATURE_32 ('P','o','r','t') ///< ESL_PORT memory signature
-typedef enum
-{
- NETWORK_TYPE_UNKNOWN = 0,
- NETWORK_TYPE_RAW,
- NETWORK_TYPE_TCP4,
- NETWORK_TYPE_TCP6,
- NETWORK_TYPE_UDP4,
- NETWORK_TYPE_UDP6
-} NETWORK_TYPE;
+/**
+ Socket states
+**/
typedef enum
{
SOCKET_STATE_NOT_CONFIGURED = 0, ///< socket call was successful
@@ -67,6 +66,10 @@ typedef enum
SOCKET_STATE_CLOSED ///< Close call was successful
} SOCKET_STATE;
+
+/**
+ Port states
+**/
typedef enum
{
PORT_STATE_ALLOCATED = 0, ///< Port allocated
@@ -74,102 +77,164 @@ typedef enum
PORT_STATE_RX_ERROR, ///< Receive error detected
//
- // Close state must be last in the list
+ // Close state must be last in the list!
+ //
+ // Using < <= > >= in tests code to detect port close state
+ // machine has started
//
PORT_STATE_CLOSE_STARTED, ///< Close started on port
PORT_STATE_CLOSE_TX_DONE, ///< Transmits shutdown
- PORT_STATE_CLOSE_RX_DONE, ///< Receives shutdown
- PORT_STATE_CLOSE_DONE ///< Port close operation complete
+ PORT_STATE_CLOSE_DONE, ///< Port close operation complete
+ PORT_STATE_CLOSE_RX_DONE ///< Receives shutdown
} PORT_STATE;
//------------------------------------------------------------------------------
// Data Types
//------------------------------------------------------------------------------
-typedef struct _DT_PACKET DT_PACKET; ///< Forward declaration
-typedef struct _DT_PORT DT_PORT; ///< Forward declaration
-typedef struct _DT_SOCKET DT_SOCKET; ///< Forward declaration
+typedef struct _ESL_IO_MGMT ESL_IO_MGMT;///< Forward declaration
+typedef struct _ESL_PACKET ESL_PACKET; ///< Forward declaration
+typedef struct _ESL_PORT ESL_PORT; ///< Forward declaration
+typedef struct _ESL_SOCKET ESL_SOCKET; ///< Forward declaration
+/**
+ Receive context for SOCK_RAW sockets using IPv4.
+**/
+typedef struct
+{
+ EFI_IP4_RECEIVE_DATA * pRxData; ///< Receive operation description
+} ESL_IP4_RX_DATA;
+
+
+/**
+ Transmit context for SOCK_RAW sockets using IPv4.
+**/
+typedef struct
+{
+ EFI_IP4_OVERRIDE_DATA Override; ///< Override data
+ EFI_IP4_TRANSMIT_DATA TxData; ///< Transmit operation description
+ UINT8 Buffer[ 1 ]; ///< Data buffer
+} ESL_IP4_TX_DATA;
+
+
+/**
+ Receive context for SOCK_STREAM and SOCK_SEQPACKET sockets using TCPv4.
+**/
typedef struct
{
EFI_TCP4_RECEIVE_DATA RxData; ///< Receive operation description
- size_t ValidBytes; ///< Length of valid data in bytes
- UINT8 * pBuffer; ///< Current data pointer
- UINT8 Buffer [ RX_PACKET_DATA ]; ///< Data buffer
-} DT_TCP4_RX_DATA;
+ UINT8 Buffer[ RX_PACKET_DATA ]; ///< Data buffer
+} ESL_TCP4_RX_DATA;
+
+/**
+ Transmit context for SOCK_STREAM and SOCK_SEQPACKET sockets using TCPv4.
+**/
typedef struct
{
EFI_TCP4_TRANSMIT_DATA TxData; ///< Transmit operation description
- UINT8 Buffer [ 1 ]; ///< Data buffer
-} DT_TCP4_TX_DATA;
+ UINT8 Buffer[ 1 ]; ///< Data buffer
+} ESL_TCP4_TX_DATA;
+
+/**
+ Receive context for SOCK_DGRAM sockets using UDPv4.
+**/
typedef struct
{
- EFI_UDP4_SESSION_DATA Session; ///< * Remote network address
- EFI_UDP4_RECEIVE_DATA * pRxData; ///< * Receive operation description
-} DT_UDP4_RX_DATA;
+ EFI_UDP4_SESSION_DATA Session; ///< Remote network address
+ EFI_UDP4_RECEIVE_DATA * pRxData; ///< Receive operation description
+} ESL_UDP4_RX_DATA;
+
+/**
+ Transmit context for SOCK_DGRAM sockets using UDPv4.
+**/
typedef struct
{
EFI_UDP4_SESSION_DATA Session; ///< Remote network address
EFI_UDP4_TRANSMIT_DATA TxData; ///< Transmit operation description
- UINT8 Buffer [ 1 ]; ///< Data buffer
-} DT_UDP4_TX_DATA;
+ UINTN RetransmitCount; ///< Retransmit to handle ARP negotiation
+ UINT8 Buffer[ 1 ]; ///< Data buffer
+} ESL_UDP4_TX_DATA;
+
-typedef struct _DT_PACKET {
- DT_PACKET * pNext; ///< Next packet in the receive list
+/**
+ Network specific context for transmit and receive packets.
+**/
+typedef struct _ESL_PACKET {
+ ESL_PACKET * pNext; ///< Next packet in the receive list
size_t PacketSize; ///< Size of this data structure
+ size_t ValidBytes; ///< Length of valid data in bytes
+ UINT8 * pBuffer; ///< Current data pointer
union {
- DT_TCP4_RX_DATA Tcp4Rx; ///< Receive operation description
- DT_TCP4_TX_DATA Tcp4Tx; ///< Transmit operation description
- DT_UDP4_RX_DATA Udp4Rx; ///< Receive operation description
- DT_UDP4_TX_DATA Udp4Tx; ///< Transmit operation description
- } Op;
-} GCC_DT_PACKET;
+ ESL_IP4_RX_DATA Ip4Rx; ///< Receive operation description
+ ESL_IP4_TX_DATA Ip4Tx; ///< Transmit operation description
+ ESL_TCP4_RX_DATA Tcp4Rx; ///< Receive operation description
+ ESL_TCP4_TX_DATA Tcp4Tx; ///< Transmit operation description
+ ESL_UDP4_RX_DATA Udp4Rx; ///< Receive operation description
+ ESL_UDP4_TX_DATA Udp4Tx; ///< Transmit operation description
+ } Op; ///< Network specific context
+} GCC_ESL_PACKET;
/**
Service control structure
The driver uses this structure to manage the network devices.
**/
-typedef struct _DT_SERVICE {
+typedef struct _ESL_SERVICE {
UINTN Signature; ///< Structure identification
//
// Links
//
- DT_SERVICE * pNext; ///< Next service in the service list
+ ESL_SERVICE * pNext; ///< Next service in the service list
//
// Service data
//
- CONST DT_SOCKET_BINDING * pSocketBinding; ///< Name and shutdown routine
- EFI_HANDLE Controller; ///< Controller for the service
- VOID * pInterface; ///< Network layer service binding interface
+ CONST ESL_SOCKET_BINDING * pSocketBinding; ///< Name and shutdown routine
+ EFI_HANDLE Controller; ///< Controller for the service
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding; ///< Network layer service binding interface
//
// Network data
//
- NETWORK_TYPE NetworkType; ///< Type of network service
- DT_PORT * pPortList; ///< List of ports using this service
-}GCC_DT_SERVICE;
+ ESL_PORT * pPortList; ///< List of ports using this service
+}GCC_ESL_SERVICE;
/**
- Start the close operation on a TCP4 port.
+ IO management structure
- @param [in] pPort Address of the port structure.
- @param [in] bAbort Set TRUE to abort active transfers
- @param [in] DebugFlags Flags for debug messages
+ This structure manages a single operation with the network.
+**/
+typedef struct _ESL_IO_MGMT {
+ ESL_IO_MGMT * pNext; ///< Next TX management structure
+ ESL_PORT * pPort; ///< Port structure address
+ ESL_PACKET * pPacket; ///< Packet structure address
+ union {
+ EFI_IP4_COMPLETION_TOKEN Ip4Rx; ///< IP4 receive token
+ EFI_IP4_COMPLETION_TOKEN Ip4Tx; ///< IP4 transmit token
+ EFI_TCP4_IO_TOKEN Tcp4Rx; ///< TCP4 receive token
+ EFI_TCP4_IO_TOKEN Tcp4Tx; ///< TCP4 transmit token
+ EFI_UDP4_COMPLETION_TOKEN Udp4Rx; ///< UDP4 receive token
+ EFI_UDP4_COMPLETION_TOKEN Udp4Tx; ///< UDP4 transmit token
+ } Token; ///< Completion token for the network operation
+};
+
+/**
+ IP4 context structure
+ The driver uses this structure to manage the IP4 connections.
**/
-typedef
-EFI_STATUS
-PFN_PORT_CLOSE_START (
- IN DT_PORT * pPort,
- IN BOOLEAN bAbort,
- IN UINTN DebugFlags
- );
+typedef struct {
+ //
+ // IP4 context
+ //
+ EFI_IP4_MODE_DATA ModeData; ///< IP4 mode data, includes configuration data
+ EFI_IPv4_ADDRESS DestinationAddress; ///< Default destination address
+} ESL_IP4_CONTEXT;
+
/**
TCP4 context structure
@@ -180,34 +245,16 @@ typedef struct {
//
// TCP4 context
//
- EFI_HANDLE Handle; ///< TCP4 port handle
- EFI_TCP4_PROTOCOL * pProtocol; ///< TCP4 protocol pointer
- EFI_TCP4_CONFIG_DATA ConfigData; ///< TCP4 configuration data
- EFI_TCP4_OPTION Option; ///< TCP4 port options
- BOOLEAN bConfigured; ///< TRUE if configuration was successful
+ EFI_TCP4_CONFIG_DATA ConfigData; ///< TCP4 configuration data
+ EFI_TCP4_OPTION Option; ///< TCP4 port options
//
// Tokens
//
- EFI_TCP4_LISTEN_TOKEN ListenToken; ///< Listen control
+ EFI_TCP4_LISTEN_TOKEN ListenToken; ///< Listen control
EFI_TCP4_CONNECTION_TOKEN ConnectToken; ///< Connection control
- EFI_TCP4_CLOSE_TOKEN CloseToken; ///< Close control
-
- //
- // Receive data management
- //
- EFI_TCP4_IO_TOKEN RxToken; ///< Receive token
- DT_PACKET * pReceivePending; ///< Receive operation in progress
-
- //
- // Transmit data management
- //
- EFI_TCP4_IO_TOKEN TxOobToken; ///< Urgent data token
- DT_PACKET * pTxOobPacket; ///< Urgent data in progress
-
- EFI_TCP4_IO_TOKEN TxToken; ///< Normal data token
- DT_PACKET * pTxPacket; ///< Normal transmit in progress
-} DT_TCP4_CONTEXT;
+ EFI_TCP4_CLOSE_TOKEN CloseToken; ///< Close control
+} ESL_TCP4_CONTEXT;
/**
UDP4 context structure
@@ -218,24 +265,41 @@ typedef struct {
//
// UDP4 context
//
- EFI_HANDLE Handle; ///< UDP4 port handle
- EFI_UDP4_PROTOCOL * pProtocol; ///< UDP4 protocol pointer
EFI_UDP4_CONFIG_DATA ConfigData; ///< UDP4 configuration data
- BOOLEAN bConfigured; ///< TRUE if configuration was successful
+} ESL_UDP4_CONTEXT;
- //
- // Receive data management
- //
- EFI_UDP4_COMPLETION_TOKEN RxToken;///< Receive token
- DT_PACKET * pReceivePending; ///< Receive operation in progress
- //
- // Transmit data management
- //
- EFI_UDP4_COMPLETION_TOKEN TxToken;///< Transmit token
- DT_PACKET * pTxPacket; ///< Transmit in progress
-} DT_UDP4_CONTEXT;
+/**
+ Configure the network layer.
+
+ @param [in] pProtocol Protocol structure address
+ @param [in] pConfigData Address of the confiuration data
+
+ @return Returns EFI_SUCCESS if the operation is successfully
+ started.
+**/
+typedef
+EFI_STATUS
+(* PFN_NET_CONFIGURE) (
+ IN VOID * pProtocol,
+ IN VOID * pConfigData
+ );
+
+/**
+ Hand an I/O operation to the network layer.
+
+ @param [in] pProtocol Protocol structure address
+ @param [in] pToken Completion token address
+ @return Returns EFI_SUCCESS if the operation is successfully
+ started.
+**/
+typedef
+EFI_STATUS
+(* PFN_NET_IO_START) (
+ IN VOID * pProtocol,
+ IN VOID * pToken
+ );
/**
Port control structure
@@ -243,240 +307,75 @@ typedef struct {
The driver uses this structure to manager the socket's connection
with the network driver.
**/
-typedef struct _DT_PORT {
+typedef struct _ESL_PORT {
UINTN Signature; ///< Structure identification
//
// List links
//
- DT_PORT * pLinkService; ///< Link in service port list
- DT_PORT * pLinkSocket; ///< Link in socket port list
+ ESL_PORT * pLinkService; ///< Link in service port list
+ ESL_PORT * pLinkSocket; ///< Link in socket port list
//
// Structures
//
- DT_SERVICE * pService; ///< Service for this port
- DT_SOCKET * pSocket; ///< Socket for this port
-// PFN_CLOSE_PORT pfnClosePort; ///< Routine to immediately close the port
- PFN_PORT_CLOSE_START * pfnCloseStart; ///< Routine to start closing the port
-
- //
- // Protocol specific management data
- //
- PORT_STATE State; ///< State of the port
- UINTN DebugFlags; ///< Debug flags used to close the port
- BOOLEAN bCloseNow; ///< TRUE = Close the port immediately
-
- union {
- DT_TCP4_CONTEXT Tcp4; ///< TCPv4 management data
- DT_UDP4_CONTEXT Udp4; ///< UDPv4 management data
- } Context;
-}GCC_DT_PORT;
-
-/**
- Socket control structure
-
- The driver uses this structure to manage the socket.
-**/
-typedef struct _DT_SOCKET {
- UINTN Signature; ///< Structure identification
-
- //
- // Protocol binding
- //
- EFI_SOCKET_PROTOCOL SocketProtocol; ///< Socket protocol declaration
+ ESL_SERVICE * pService; ///< Service for this port
+ ESL_SOCKET * pSocket; ///< Socket for this port
//
- // Socket management
+ // Eliminate the pService references during port close
//
- DT_SOCKET * pNext; ///< Next socket in the list of sockets
- int errno; ///< Error information for this socket
- EFI_STATUS Status; ///< Asyncronous error information for this socket
- SOCKET_STATE State; ///< Socket state
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding; ///< Service binding for network layer
+ CONST ESL_SOCKET_BINDING * pSocketBinding; ///< Socket binding for network layer
//
- // Socket data
+ // Port management
//
- int Domain; ///< Specifies family of protocols
- int Type; ///< Specifies how to make network connection
- int Protocol; ///< Specifies lower layer protocol to use
- BOOLEAN bConfigured; ///< Set after the socket is configured
-
- BOOLEAN bRxDisable; ///< Receive disabled via shutdown
- size_t RxBytes; ///< Total Rx bytes
- size_t RxOobBytes; ///< Urgent Rx bytes
- EFI_STATUS RxError; ///< Error during receive
-
- BOOLEAN bTxDisable; ///< Transmit disabled via shutdown
- size_t TxBytes; ///< Normal Tx bytes
- size_t TxOobBytes; ///< Urgent Tx bytes
- EFI_STATUS TxError; ///< Error during transmit
-
- //
- // Pending connection data
- //
- BOOLEAN bConnected; ///< Set when connected, cleared by poll
- EFI_STATUS ConnectStatus; ///< Connection status
- UINTN MaxFifoDepth; ///< Maximum FIFO depth
- UINTN FifoDepth; ///< Number of sockets in the FIFO
- DT_SOCKET * pFifoHead; ///< Head of the FIFO
- DT_SOCKET * pFifoTail; ///< Tail of the FIFO
- DT_SOCKET * pNextConnection; ///< Link in the FIFO
-
- //
- // Network use
- //
- DT_PORT * pPortList; ///< List of ports managed by this socket
- EFI_EVENT WaitAccept; ///< Wait for accept completion
-
- //
- // Receive data management
- //
- UINT32 MaxRxBuf; ///< Maximum size of the receive buffer
- struct timeval RxTimeout; ///< Receive timeout
- DT_PACKET * pRxFree; ///< Free packet list
- DT_PACKET * pRxOobPacketListHead; ///< Urgent data list head
- DT_PACKET * pRxOobPacketListTail; ///< Urgent data list tail
- DT_PACKET * pRxPacketListHead; ///< Normal data list head
- DT_PACKET * pRxPacketListTail; ///< Normal data list tail
+ EFI_HANDLE Handle; ///< Network port handle
+ PORT_STATE State; ///< State of the port
+ UINTN DebugFlags; ///< Debug flags used to close the port
+ BOOLEAN bCloseNow; ///< TRUE = Close the port immediately
+ BOOLEAN bConfigured; ///< TRUE = Configure call made to network layer
+ PFN_NET_CONFIGURE pfnConfigure; ///< Configure the network layer
//
// Transmit data management
//
- UINT32 MaxTxBuf; ///< Maximum size of the transmit buffer
- DT_PACKET * pTxOobPacketListHead; ///< Urgent data list head
- DT_PACKET * pTxOobPacketListTail; ///< Urgent data list tail
- DT_PACKET * pTxPacketListHead; ///< Normal data list head
- DT_PACKET * pTxPacketListTail; ///< Normal data list tail
-}GCC_DT_SOCKET;
-
-#define SOCKET_FROM_PROTOCOL(a) CR(a, DT_SOCKET, SocketProtocol, SOCKET_SIGNATURE) ///< Locate DT_SOCKET from protocol
-
-/**
- Socket layer control structure
-
- The driver uses this structure to manage the driver.
-**/
-typedef struct {
- UINTN Signature; ///< Structure identification
-
- //
- // Service binding interface
- //
- EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;///< Driver's binding
+ BOOLEAN bTxFlowControl; ///< TX flow control applied
+ PFN_NET_IO_START pfnTxStart; ///< Start a transmit on the network
+ ESL_IO_MGMT * pTxActive; ///< Normal data queue
+ ESL_IO_MGMT * pTxFree; ///< Normal free queue
- //
- // Image data
- //
- EFI_HANDLE ImageHandle; ///< Image handle
+ ESL_IO_MGMT * pTxOobActive; ///< Urgent data queue
+ ESL_IO_MGMT * pTxOobFree; ///< Urgent free queue
//
- // Network services
+ // Receive data management
//
- DT_SERVICE * pTcp4List; ///< List of Tcp4 services
- DT_SERVICE * pUdp4List; ///< List of Udp4 services
+ PFN_NET_IO_START pfnRxCancel; ///< Cancel a receive on the network
+ PFN_NET_IO_START pfnRxStart; ///< Start a receive on the network
+ ESL_IO_MGMT * pRxActive; ///< Active receive operation queue
+ ESL_IO_MGMT * pRxFree; ///< Free structure queue
//
- // Socket management
- //
- DT_SOCKET * pSocketList; ///< List of sockets
-
- //
- // TCP4 service
+ // Protocol specific management data
//
- UINTN TcpCloseMax4; ///< Number of entries in the ring buffer
- UINTN TcpCloseIn4; ///< Offset into TcpClose4 ring buffer - Close request
- UINTN TcpCloseOut4; ///< Offset into TcpClose4 ring buffer - Close operation
- EFI_TCP4_PROTOCOL ** ppTcpClose4; ///< Ring buffer to close TCP4 ports
-} DT_LAYER;
-
-#define LAYER_FROM_SERVICE(a) CR(a, DT_LAYER, ServiceBinding, LAYER_SIGNATURE) ///< Locate DT_LAYER from service binding
-
-//------------------------------------------------------------------------------
-// Data
-//------------------------------------------------------------------------------
-
-extern DT_LAYER mEslLayer;
-
-//------------------------------------------------------------------------------
-// Socket Support Routines
-//------------------------------------------------------------------------------
-
-/**
- Allocate and initialize a DT_SOCKET structure.
-
- The ::SocketAllocate() function allocates a DT_SOCKET structure
- and installs a protocol on ChildHandle. If pChildHandle is a
- pointer to NULL, then a new handle is created and returned in
- pChildHandle. If pChildHandle is not a pointer to NULL, then
- the protocol installs on the existing pChildHandle.
-
- @param [in, out] pChildHandle Pointer to the handle of the child to create.
- If it is NULL, then a new handle is created.
- If it is a pointer to an existing UEFI handle,
- then the protocol is added to the existing UEFI
- handle.
- @param [in] DebugFlags Flags for debug messages
- @param [in, out] ppSocket The buffer to receive the DT_SOCKET structure address.
-
- @retval EFI_SUCCESS The protocol was added to ChildHandle.
- @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
- the child
- @retval other The child handle was not created
-
-**/
-EFI_STATUS
-EFIAPI
-EslSocketAllocate (
- IN OUT EFI_HANDLE * pChildHandle,
- IN UINTN DebugFlags,
- IN OUT DT_SOCKET ** ppSocket
- );
-
-/**
- Allocate a packet for a receive or transmit operation
-
- @param [in] ppPacket Address to receive the DT_PACKET structure
- @param [in] LengthInBytes Length of the packet structure
- @param [in] DebugFlags Flags for debug messages
-
- @retval EFI_SUCCESS - The packet was allocated successfully
-
- **/
-EFI_STATUS
-EslSocketPacketAllocate (
- IN DT_PACKET ** ppPacket,
- IN size_t LengthInBytes,
- IN UINTN DebugFlags
- );
-
-/**
- Free a packet used for receive or transmit operation
-
- @param [in] pPacket Address of the DT_PACKET structure
- @param [in] DebugFlags Flags for debug messages
-
- @retval EFI_SUCCESS - The packet was allocated successfully
-
- **/
-EFI_STATUS
-EslSocketPacketFree (
- IN DT_PACKET * pPacket,
- IN UINTN DebugFlags
- );
-
-//------------------------------------------------------------------------------
-// Tcp4 Routines
-//------------------------------------------------------------------------------
+ union {
+ VOID * v; ///< VOID pointer
+ EFI_IP4_PROTOCOL * IPv4; ///< IP4 protocol pointer
+ EFI_TCP4_PROTOCOL * TCPv4; ///< TCP4 protocol pointer
+ EFI_UDP4_PROTOCOL * UDPv4; ///< UDP4 protocol pointer
+ } pProtocol; ///< Protocol structure address
+ union {
+ ESL_IP4_CONTEXT Ip4; ///< IPv4 management data
+ ESL_TCP4_CONTEXT Tcp4; ///< TCPv4 management data
+ ESL_UDP4_CONTEXT Udp4; ///< UDPv4 management data
+ } Context; ///< Network specific context
+}GCC_ESL_PORT;
/**
Accept a network connection.
- The SocketAccept routine waits for a network connection to the socket.
- It is able to return the remote network address to the caller if
- requested.
-
@param [in] pSocket Address of the socket structure.
@param [in] pSockAddr Address of a buffer to receive the remote
@@ -490,293 +389,276 @@ EslSocketPacketFree (
@retval Others Remote address not available
**/
+typedef
EFI_STATUS
-EslTcpAccept4 (
- IN DT_SOCKET * pSocket,
+(* PFN_API_ACCEPT) (
+ IN ESL_SOCKET * pSocket,
IN struct sockaddr * pSockAddr,
IN OUT socklen_t * pSockAddrLength
);
/**
- Bind a name to a socket.
-
- The ::TcpBind4 routine connects a name to A TCP4 stack on the local machine.
-
- @param [in] pSocket Address of the socket structure.
-
- @param [in] pSockAddr Address of a sockaddr structure that contains the
- connection point on the local machine. An IPv4 address
- of INADDR_ANY specifies that the connection is made to
- all of the network stacks on the platform. Specifying a
- specific IPv4 address restricts the connection to the
- network stack supporting that address. Specifying zero
- for the port causes the network layer to assign a port
- number from the dynamic range. Specifying a specific
- port number causes the network layer to use that port.
-
- @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.
-
- @retval EFI_SUCCESS - Socket successfully created
-
- **/
-EFI_STATUS
-EslTcpBind4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
- );
-
-/**
Poll for completion of the connection attempt.
- The ::TcpConnectPoll4 routine determines when the connection
- attempt transitions from being in process to being complete.
-
- @param [in] pSocket Address of the socket structure.
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
@retval EFI_SUCCESS The connection was successfully established.
@retval EFI_NOT_READY The connection is in progress, call this routine again.
@retval Others The connection attempt failed.
**/
+typedef
EFI_STATUS
-EslTcpConnectPoll4 (
- IN DT_SOCKET * pSocket
+(* PFN_API_CONNECT_POLL) (
+ IN ESL_SOCKET * pSocket
);
/**
- Connect to a remote system via the network.
+ Attempt to connect to a remote TCP port
- The ::TcpConnectStart4= routine starts the connection processing
- for a TCP4 port.
+ This routine starts the connection processing for a SOCK_STREAM
+ or SOCK_SEQPAKCET socket using the TCP network layer.
- @param [in] pSocket Address of the socket structure.
+ This routine is called by ::EslSocketConnect to initiate the TCP
+ network specific connect operations.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
- @param [in] pSockAddr Network address of the remote system.
-
- @param [in] SockAddrLength Length in bytes of the network address.
-
@retval EFI_SUCCESS The connection was successfully established.
@retval EFI_NOT_READY The connection is in progress, call this routine again.
@retval Others The connection attempt failed.
**/
+typedef
EFI_STATUS
-EslTcpConnectStart4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
+(* PFN_API_CONNECT_START) (
+ IN ESL_SOCKET * pSocket
);
/**
- Initialize the TCP4 service.
-
- This routine initializes the TCP4 service after its service binding
- protocol was located on a controller.
+ Get the local socket address
- @param [in] pService DT_SERVICE structure address
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @retval EFI_SUCCESS The service was properly initialized
- @retval other A failure occurred during the service initialization
+ @param [out] pAddress Network address to receive the local system address
**/
-EFI_STATUS
-EFIAPI
-EslTcpInitialize4 (
- IN DT_SERVICE * pService
+typedef
+VOID
+(* PFN_API_LOCAL_ADDR_GET) (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
);
/**
- Get the local socket address
+ Set the local port address.
- @param [in] pSocket Address of the socket structure.
+ This routine sets the local port address.
- @param [out] pAddress Network address to receive the local system address
+ This support routine is called by ::EslSocketPortAllocate.
- @param [in,out] pAddressLength Length of the local network address structure
+ @param [in] ppPort Address of an ESL_PORT structure
+ @param [in] pSockAddr Address of a sockaddr structure that contains the
+ connection point on the local machine. An IPv4 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv4 address restricts the connection to the
+ network stack supporting that address. Specifying zero
+ for the port causes the network layer to assign a port
+ number from the dynamic range. Specifying a specific
+ port number causes the network layer to use that port.
+ @param [in] bBindTest TRUE = run bind testing
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
+ @retval EFI_SUCCESS The operation was successful
-**/
+ **/
+typedef
EFI_STATUS
-EslTcpGetLocalAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+(* PFN_API_LOCAL_ADDR_SET) (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest
);
/**
- Get the remote socket address
-
- @param [in] pSocket Address of the socket structure.
-
- @param [out] pAddress Network address to receive the remote system address
+ Determine if the socket is configured.
- @param [in,out] pAddressLength Length of the remote network address structure
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
+ @param [in] pSocket Address of a ESL_SOCKET structure
+
+ @retval EFI_SUCCESS - The port is connected
+ @retval EFI_NOT_STARTED - The port is not connected
-**/
-EFI_STATUS
-EslTcpGetRemoteAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+ **/
+ typedef
+ EFI_STATUS
+ (* PFN_API_IS_CONFIGURED) (
+ IN ESL_SOCKET * pSocket
);
/**
Establish the known port to listen for network connections.
- The ::Tcp4Listen routine places the port into a state that enables connection
- attempts. Connections are placed into FIFO order in a queue to be serviced
- by the application. The application calls the ::Tcp4Accept routine to remove
- the next connection from the queue and get the associated socket. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>
- documentation for the listen routine is available online for reference.
-
@param [in] pSocket Address of the socket structure.
-
+
@retval EFI_SUCCESS - Socket successfully created
@retval Other - Failed to enable the socket for listen
**/
+typedef
EFI_STATUS
-EslTcpListen4 (
- IN DT_SOCKET * pSocket
+(* PFN_API_LISTEN) (
+ IN ESL_SOCKET * pSocket
);
/**
- Process the connection attempt
-
- A system has initiated a connection attempt with a socket in the
- listen state. Attempt to complete the connection.
+ Get the option value
- @param Event The listeen completion event
+ Retrieve the protocol options one at a time by name.
- @param pPort The DT_PORT structure address
-
-**/
-VOID
-EslTcpListenComplete4 (
- IN EFI_EVENT Event,
- IN DT_PORT * pPort
- );
+ @param [in] pSocket Address of a ESL_SOCKET structure
+ @param [in] OptionName Name of the option
+ @param [out] ppOptionData Buffer to receive address of option value
+ @param [out] pOptionLength Buffer to receive the option length
-/**
- Allocate and initialize a DT_PORT structure.
-
- @param [in] pSocket Address of the socket structure.
- @param [in] pService Address of the DT_SERVICE structure.
- @param [in] ChildHandle TCP4 child handle
- @param [in] pIpAddress Buffer containing IP4 network address of the local host
- @param [in] PortNumber Tcp4 port number
- @param [in] DebugFlags Flags for debug messages
- @param [out] ppPort Buffer to receive new DT_PORT structure address
-
- @retval EFI_SUCCESS - Socket successfully created
+ @retval EFI_SUCCESS - Socket data successfully received
**/
+typedef
EFI_STATUS
-EslTcpPortAllocate4 (
- IN DT_SOCKET * pSocket,
- IN DT_SERVICE * pService,
- IN EFI_HANDLE ChildHandle,
- IN CONST UINT8 *pIpAddress,
- IN UINT16 PortNumber,
- IN UINTN DebugFlags,
- OUT DT_PORT ** ppPort
+(* PFN_API_OPTION_GET) (
+ IN ESL_SOCKET * pSocket,
+ IN int OptionName,
+ OUT CONST void ** __restrict ppOptionData,
+ OUT socklen_t * __restrict pOptionLength
);
/**
- Close a TCP4 port.
+ Set the option value
- This routine releases the resources allocated by
- ::TcpPortAllocate4().
-
- @param [in] pPort Address of the port structure.
+ Adjust the protocol options one at a time by name.
- @retval EFI_SUCCESS The port is closed
- @retval other Port close error
+ @param [in] pSocket Address of a ESL_SOCKET structure
+ @param [in] OptionName Name of the option
+ @param [in] pOptionValue Buffer containing the option value
+ @param [in] OptionLength Length of the buffer in bytes
-**/
+ @retval EFI_SUCCESS - Option successfully set
+
+ **/
+typedef
EFI_STATUS
-EslTcpPortClose4 (
- IN DT_PORT * pPort
+(* PFN_API_OPTION_SET) (
+ IN ESL_SOCKET * pSocket,
+ IN int OptionName,
+ IN CONST void * pOptionValue,
+ IN socklen_t OptionLength
);
/**
- Process the port close completion
+ Free a receive packet
+
+ This routine performs the network specific operations necessary
+ to free a receive packet.
- @param Event The close completion event
+ This routine is called by ::EslSocketPortCloseTxDone to free a
+ receive packet.
- @param pPort The DT_PORT structure address
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
+ @param [in, out] pRxBytes Address of the count of RX bytes
**/
+typedef
VOID
-EslTcpPortCloseComplete4 (
- IN EFI_EVENT Event,
- IN DT_PORT * pPort
+(* PFN_API_PACKET_FREE) (
+ IN ESL_PACKET * pPacket,
+ IN OUT size_t * pRxBytes
);
/**
- Port close state 3
+ Initialize the network specific portions of an ::ESL_PORT structure.
- Continue the close operation after the receive is complete.
+ This routine initializes the network specific portions of an
+ ::ESL_PORT structure for use by the socket.
- @param [in] pPort Address of the port structure.
+ This support routine is called by ::EslSocketPortAllocate
+ to connect the socket with the underlying network adapter
+ running the IPv4 protocol.
- @retval EFI_SUCCESS The port is closed
- @retval EFI_NOT_READY The port is still closing
- @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
- most likely the routine was called already.
+ @param [in] ppPort Address of an ESL_PORT structure
+ @param [in] DebugFlags Flags for debug messages
-**/
+ @retval EFI_SUCCESS - Socket successfully created
+
+ **/
+typedef
EFI_STATUS
-EslTcpPortCloseRxDone4 (
- IN DT_PORT * pPort
+(* PFN_API_PORT_ALLOC) (
+ IN ESL_PORT * pPort,
+ IN UINTN DebugFlags
);
/**
- Start the close operation on a TCP4 port.
+ Close a network specific port.
- @param [in] pPort Address of the port structure.
- @param [in] bAbort Set TRUE to abort active transfers
- @param [in] DebugFlags Flags for debug messages
+ This routine releases the resources allocated by the
+ network specific PortAllocate routine.
+
+ This routine is called by ::EslSocketPortCloseRxDone as
+ the last step of closing processing.
+ See the \ref PortCloseStateMachine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @retval EFI_SUCCESS The port is closed
+ @retval other Port close error
**/
+typedef
EFI_STATUS
-EslTcpPortCloseStart4 (
- IN DT_PORT * pPort,
- IN BOOLEAN bAbort,
- IN UINTN DebugFlags
+(* PFN_API_PORT_CLOSE) (
+ IN ESL_PORT * pPort
);
/**
- Port close state 2
+ Perform the network specific close operation on the port.
- Continue the close operation after the transmission is complete.
+ This routine performs the network specific operation to
+ shutdown receive operations on the port.
- @param [in] pPort Address of the port structure.
+ This routine is called by the ::EslSocketPortCloseTxDone
+ routine after the port completes all of the transmission.
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @retval EFI_SUCCESS The port is closed, not normally returned
@retval EFI_NOT_READY The port is still closing
@retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
most likely the routine was called already.
**/
+typedef
EFI_STATUS
-EslTcpPortCloseTxDone4 (
- IN DT_PORT * pPort
+(* PFN_API_PORT_CLOSE_OP) (
+ IN ESL_PORT * pPort
);
/**
Receive data from a network connection.
+ This routine attempts to return buffered data to the caller. The
+ data is removed from the urgent queue if the message flag MSG_OOB
+ is specified, otherwise data is removed from the normal queue.
+ See the \ref ReceiveEngine section.
+
+ This routine is called by ::EslSocketReceive to handle the network
+ specific receive operation.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @param [in] pSocket Address of a DT_SOCKET structure
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
- @param [in] Flags Message control flags
+ @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
@param [in] BufferLength Length of the the buffer
@@ -786,550 +668,850 @@ EslTcpPortCloseTxDone4 (
@param [out] pAddress Network address to receive the remote system address
- @param [in,out] pAddressLength Length of the remote network address structure
+ @param [out] pSkipBytes Address to receive the number of bytes skipped
- @retval EFI_SUCCESS - Socket data successfully received
+ @return Returns the address of the next free byte in the buffer.
**/
-EFI_STATUS
-EslTcpReceive4 (
- IN DT_SOCKET * pSocket,
- IN INT32 Flags,
+typedef
+UINT8 *
+(* PFN_API_RECEIVE) (
+ IN ESL_PORT * pPort,
+ IN ESL_PACKET * pPacket,
+ IN BOOLEAN * pbConsumePacket,
IN size_t BufferLength,
IN UINT8 * pBuffer,
OUT size_t * pDataLength,
OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+ OUT size_t * pSkipBytes
);
/**
- Cancel the receive operations
+ Get the remote socket address
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @retval EFI_SUCCESS - The cancel was successful
+ @param [in] pPort Address of an ::ESL_PORT structure.
- **/
-EFI_STATUS
-EslTcpRxCancel4 (
- IN DT_SOCKET * pSocket
+ @param [out] pAddress Network address to receive the remote system address
+
+**/
+typedef
+VOID
+(* PFN_API_REMOTE_ADDR_GET) (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
);
/**
- Process the receive completion
+ Set the remote address
- Buffer the data that was just received.
+ This routine sets the remote address in the port.
- @param Event The receive completion event
+ This routine is called by ::EslSocketConnect to specify the
+ remote network address.
- @param pPort The DT_PORT structure address
+ @param [in] pPort Address of an ::ESL_PORT structure.
-**/
-VOID
-EslTcpRxComplete4 (
- IN EFI_EVENT Event,
- IN DT_PORT * pPort
- );
+ @param [in] pSockAddr Network address of the remote system.
-/**
- Start a receive operation
+ @param [in] SockAddrLength Length in bytes of the network address.
- @param [in] pPort Address of the DT_PORT structure.
+ @retval EFI_SUCCESS The operation was successful
**/
-VOID
-EslTcpRxStart4 (
- IN DT_PORT * pPort
+typedef
+EFI_STATUS
+(* PFN_API_REMOTE_ADDR_SET) (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN socklen_t SockAddrLength
);
/**
- Shutdown the TCP4 service.
+ Process the receive completion
+
+ This routine handles the receive completion event.
- This routine undoes the work performed by ::TcpInitialize4.
+ This routine is called by the low level network driver when
+ data is received.
- @param [in] pService DT_SERVICE structure address
+ @param [in] Event The receive completion event
+
+ @param [in] pIo The address of an ::ESL_IO_MGMT structure
**/
+typedef
VOID
-EFIAPI
-EslTcpShutdown4 (
- IN DT_SERVICE * pService
+(* PFN_API_RX_COMPLETE) (
+ IN EFI_EVENT Event,
+ IN ESL_IO_MGMT * pIo
);
/**
- Determine if the socket is configured.
+ Start a receive operation
+ This routine prepares a packet for the receive operation.
+ See the \ref ReceiveEngine section.
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @retval EFI_SUCCESS - The port is connected
- @retval EFI_NOT_STARTED - The port is not connected
+ This support routine is called by EslSocketRxStart.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure.
**/
- EFI_STATUS
- EslTcpSocketIsConfigured4 (
- IN DT_SOCKET * pSocket
+typedef
+VOID
+(* PFN_API_RX_START) (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT * pIo
);
/**
Buffer data for transmission over a network connection.
- This routine is called by the socket layer API to buffer
- data for transmission. When necessary, this routine will
- start the transmit engine that performs the data transmission
- on the network connection.
+ @param [in] pSocket Address of a ESL_SOCKET structure
- @param [in] pSocket Address of a DT_SOCKET structure
-
@param [in] Flags Message control flags
-
+
@param [in] BufferLength Length of the the buffer
-
+
@param [in] pBuffer Address of a buffer to receive the data.
-
+
@param [in] pDataLength Number of received data bytes in the buffer.
+ @param [in] pAddress Network address of the remote system address
+
+ @param [in] AddressLength Length of the remote network address structure
+
@retval EFI_SUCCESS - Socket data successfully buffered
- **/
+**/
+typedef
EFI_STATUS
-EslTcpTxBuffer4 (
- IN DT_SOCKET * pSocket,
+(* PFN_API_TRANSMIT) (
+ IN ESL_SOCKET * pSocket,
IN int Flags,
IN size_t BufferLength,
IN CONST UINT8 * pBuffer,
- OUT size_t * pDataLength
+ OUT size_t * pDataLength,
+ IN const struct sockaddr * pAddress,
+ IN socklen_t AddressLength
);
/**
- Process the normal data transmit completion
+ Process the transmit completion
+
+ This routine calls ::EslSocketTxComplete to handle the
+ transmit completion.
+
+ This routine is called by the network layers upon the completion
+ of a transmit operation.
- @param Event The normal transmit completion event
+ @param [in] Event The urgent transmit completion event
- @param pPort The DT_PORT structure address
+ @param [in] pIo The ESL_IO_MGMT structure address
**/
+typedef
VOID
-EslTcpTxComplete4 (
+(* PFN_API_TX_COMPLETE) (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_IO_MGMT * pIo
);
/**
- Process the urgent data transmit completion
+ Socket type control structure
+
+ This driver uses this structure to define the API for the socket type.
+**/
+typedef struct {
+ CONST CHAR8 * pName; ///< Protocol name
+ int DefaultProtocol; ///< Default protocol
+ UINTN ConfigDataOffset; ///< Offset in ::ESL_PORT to the configuration data
+ UINTN ServiceListOffset; ///< Offset in ::ESL_LAYER for the list of services
+ socklen_t MinimumAddressLength; ///< Minimum address length in bytes
+ socklen_t AddressLength; ///< Address length in bytes
+ sa_family_t AddressFamily; ///< Address family
+ UINTN RxPacketBytes; ///< Length of the RX packet allocation
+ UINTN RxZeroBytes; ///< Number of bytes to zero in RX packet
+ UINTN RxBufferOffset; ///< Offset of buffer address in ESL_IO_MGMT structure
+ BOOLEAN bOobSupported; ///< TRUE if out-of-band messages are supported
+ int BindTestErrno; ///< errno value if EslSocketBindTest fails
+ PFN_API_ACCEPT pfnAccept; ///< Accept a network connection
+ PFN_API_CONNECT_POLL pfnConnectPoll; ///< Poll for connection complete
+ PFN_API_CONNECT_START pfnConnectStart; ///< Start the connection to a remote system
+ PFN_API_IS_CONFIGURED pfnIsConfigured; ///< Determine if the socket is configured
+ PFN_API_LOCAL_ADDR_GET pfnLocalAddrGet; ///< Get the local address
+ PFN_API_LOCAL_ADDR_SET pfnLocalAddrSet; ///< Set the local address
+ PFN_API_LISTEN pfnListen; ///< Listen for connections on known server port
+ PFN_API_OPTION_GET pfnOptionGet; ///< Get the option value
+ PFN_API_OPTION_SET pfnOptionSet; ///< Set the option value
+ PFN_API_PACKET_FREE pfnPacketFree; ///< Free the receive packet
+ PFN_API_PORT_ALLOC pfnPortAllocate; ///< Allocate the network specific resources for the port
+ PFN_API_PORT_CLOSE pfnPortClose; ///< Close the network specific resources for the port
+ PFN_API_PORT_CLOSE_OP pfnPortCloseOp; ///< Perform the close operation on the port
+ BOOLEAN bPortCloseComplete; ///< TRUE = Close is complete after close operation
+ PFN_API_RECEIVE pfnReceive; ///< Attempt to receive some data
+ PFN_API_REMOTE_ADDR_GET pfnRemoteAddrGet; ///< Get remote address
+ PFN_API_REMOTE_ADDR_SET pfnRemoteAddrSet; ///< Set the remote system address
+ PFN_API_RX_COMPLETE pfnRxComplete; ///< RX completion
+ PFN_API_RX_START pfnRxStart; ///< Start a network specific receive operation
+ PFN_API_TRANSMIT pfnTransmit; ///< Attempt to buffer a packet for transmit
+ PFN_API_TX_COMPLETE pfnTxComplete; ///< TX completion for normal data
+ PFN_API_TX_COMPLETE pfnTxOobComplete; ///< TX completion for urgent data
+} ESL_PROTOCOL_API;
- @param Event The urgent transmit completion event
- @param pPort The DT_PORT structure address
+/**
+ Socket control structure
+ The driver uses this structure to manage the socket.
**/
-VOID
-EslTcpTxOobComplete4 (
- IN EFI_EVENT Event,
- IN DT_PORT * pPort
- );
+typedef struct _ESL_SOCKET {
+ UINTN Signature; ///< Structure identification
-/**
- Transmit data using a network connection.
+ //
+ // Protocol binding
+ //
+ EFI_SOCKET_PROTOCOL SocketProtocol; ///< Socket protocol declaration
+ CONST ESL_PROTOCOL_API * pApi; ///< API for the protocol
+ //
+ // Socket management
+ //
+ ESL_SOCKET * pNext; ///< Next socket in the list of sockets
+ int errno; ///< Error information for this socket
+ EFI_STATUS Status; ///< Asyncronous error information for this socket
+ SOCKET_STATE State; ///< Socket state
+ UINT32 DebugFlags; ///< Debug flags
- @param [in] pPort Address of a DT_PORT structure
- @param [in] pToken Address of either the OOB or normal transmit token
- @param [in] ppQueueHead Transmit queue head address
- @param [in] ppQueueTail Transmit queue tail address
- @param [in] ppPacket Active transmit packet address
+ //
+ // Socket options
+ //
+ BOOLEAN bListenCalled; ///< TRUE if listen was successfully called
+ BOOLEAN bOobInLine; ///< TRUE if out-of-band messages are to be received inline with normal data
+ BOOLEAN bIncludeHeader; ///< TRUE if including the IP header
- **/
-VOID
-EslTcpTxStart4 (
- IN DT_PORT * pPort,
- IN EFI_TCP4_IO_TOKEN * pToken,
- IN DT_PACKET ** ppQueueHead,
- IN DT_PACKET ** ppQueueTail,
- IN DT_PACKET ** ppPacket
- );
+ //
+ // Socket data
+ //
+ int Domain; ///< Specifies family of protocols
+ int Type; ///< Specifies how to make network connection
+ int Protocol; ///< Specifies lower layer protocol to use
+ BOOLEAN bConfigured; ///< Set after the socket is configured
-//------------------------------------------------------------------------------
-// Udp4 Routines
-//------------------------------------------------------------------------------
+ BOOLEAN bRxDisable; ///< Receive disabled via shutdown
+ size_t RxBytes; ///< Total Rx bytes
+ size_t RxOobBytes; ///< Urgent Rx bytes
+ EFI_STATUS RxError; ///< Error during receive
+
+ BOOLEAN bTxDisable; ///< Transmit disabled via shutdown
+ size_t TxBytes; ///< Normal Tx bytes
+ size_t TxOobBytes; ///< Urgent Tx bytes
+ EFI_STATUS TxError; ///< Error during transmit
+
+ //
+ // Pending connection data
+ //
+ BOOLEAN bConnected; ///< Set when connected, cleared by poll
+ EFI_STATUS ConnectStatus; ///< Connection status
+ UINTN MaxFifoDepth; ///< Maximum FIFO depth
+ UINTN FifoDepth; ///< Number of sockets in the FIFO
+ ESL_SOCKET * pFifoHead; ///< Head of the FIFO
+ ESL_SOCKET * pFifoTail; ///< Tail of the FIFO
+ ESL_SOCKET * pNextConnection; ///< Link in the FIFO
+
+ //
+ // Network use
+ //
+ ESL_PORT * pPortList; ///< List of ports managed by this socket
+ EFI_EVENT WaitAccept; ///< Wait for accept completion
+
+ //
+ // Receive data management
+ //
+ UINT32 MaxRxBuf; ///< Maximum size of the receive buffer
+ struct timeval RxTimeout; ///< Receive timeout
+ ESL_PACKET * pRxFree; ///< Free packet list
+ ESL_PACKET * pRxOobPacketListHead;///< Urgent data list head
+ ESL_PACKET * pRxOobPacketListTail;///< Urgent data list tail
+ ESL_PACKET * pRxPacketListHead; ///< Normal data list head
+ ESL_PACKET * pRxPacketListTail; ///< Normal data list tail
+
+ //
+ // Transmit data management
+ //
+ UINTN TxPacketOffset; ///< Offset for data pointer in ::ESL_PACKET
+ UINTN TxTokenEventOffset; ///< Offset to the Event in the TX token
+ UINTN TxTokenOffset; ///< Offset for data pointer in TX token
+ UINT32 MaxTxBuf; ///< Maximum size of the transmit buffer
+ ESL_PACKET * pTxOobPacketListHead;///< Urgent data list head
+ ESL_PACKET * pTxOobPacketListTail;///< Urgent data list tail
+ ESL_PACKET * pTxPacketListHead; ///< Normal data list head
+ ESL_PACKET * pTxPacketListTail; ///< Normal data list tail
+}GCC_ESL_SOCKET;
+
+#define SOCKET_FROM_PROTOCOL(a) CR (a, ESL_SOCKET, SocketProtocol, SOCKET_SIGNATURE) ///< Locate ESL_SOCKET from protocol
/**
- Bind a name to a socket.
+ Socket layer control structure
- The ::UdpBind4 routine connects a name to a UDP4 stack on the local machine.
+ The driver uses this structure to manage the driver.
+**/
+typedef struct {
+ UINTN Signature; ///< Structure identification
- @param [in] pSocket Address of the socket structure.
+ //
+ // Service binding interface
+ //
+ CONST EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding; ///< Driver's binding
- @param [in] pSockAddr Address of a sockaddr structure that contains the
- connection point on the local machine. An IPv4 address
- of INADDR_ANY specifies that the connection is made to
- all of the network stacks on the platform. Specifying a
- specific IPv4 address restricts the connection to the
- network stack supporting that address. Specifying zero
- for the port causes the network layer to assign a port
- number from the dynamic range. Specifying a specific
- port number causes the network layer to use that port.
+ //
+ // Image data
+ //
+ EFI_HANDLE ImageHandle; ///< Image handle
- @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.
+ //
+ // Network services
+ //
+ ESL_SERVICE * pIp4List; ///< List of Ip4 services
+ ESL_SERVICE * pTcp4List; ///< List of Tcp4 services
+ ESL_SERVICE * pUdp4List; ///< List of Udp4 services
- @retval EFI_SUCCESS - Socket successfully created
+ //
+ // Socket management
+ //
+ ESL_SOCKET * pSocketList; ///< List of sockets
+} ESL_LAYER;
- **/
-EFI_STATUS
-EslUdpBind4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
- );
+#define LAYER_FROM_SERVICE(a) CR (a, ESL_LAYER, ServiceBinding, LAYER_SIGNATURE) ///< Locate ESL_LAYER from service binding
-/**
- Initialize the UDP4 service.
+//------------------------------------------------------------------------------
+// Data
+//------------------------------------------------------------------------------
+
+extern ESL_LAYER mEslLayer;
- This routine initializes the UDP4 service after its service binding
- protocol was located on a controller.
+extern CONST ESL_PROTOCOL_API cEslIp4Api;
+extern CONST ESL_PROTOCOL_API cEslTcp4Api;
+extern CONST ESL_PROTOCOL_API cEslUdp4Api;
- @param [in] pService DT_SERVICE structure address
+extern CONST EFI_SERVICE_BINDING_PROTOCOL mEfiServiceBinding;
+
+//------------------------------------------------------------------------------
+// Socket Support Routines
+//------------------------------------------------------------------------------
+
+/**
+ Allocate and initialize a ESL_SOCKET structure.
+
+ This support function allocates an ::ESL_SOCKET structure
+ and installs a protocol on ChildHandle. If pChildHandle is a
+ pointer to NULL, then a new handle is created and returned in
+ pChildHandle. If pChildHandle is not a pointer to NULL, then
+ the protocol installs on the existing pChildHandle.
- @retval EFI_SUCCESS The service was properly initialized
- @retval other A failure occurred during the service initialization
+ @param [in, out] pChildHandle Pointer to the handle of the child to create.
+ If it is NULL, then a new handle is created.
+ If it is a pointer to an existing UEFI handle,
+ then the protocol is added to the existing UEFI
+ handle.
+ @param [in] DebugFlags Flags for debug messages
+ @param [in, out] ppSocket The buffer to receive an ::ESL_SOCKET structure address.
+ @retval EFI_SUCCESS The protocol was added to ChildHandle.
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
+ the child
+ @retval other The child handle was not created
+
**/
EFI_STATUS
EFIAPI
-EslUdpInitialize4 (
- IN DT_SERVICE * pService
+EslSocketAllocate (
+ IN OUT EFI_HANDLE * pChildHandle,
+ IN UINTN DebugFlags,
+ IN OUT ESL_SOCKET ** ppSocket
);
/**
- Allocate and initialize a DT_PORT structure.
+ Test the bind configuration.
- @param [in] pSocket Address of the socket structure.
- @param [in] pService Address of the DT_SERVICE structure.
- @param [in] ChildHandle Udp4 child handle
- @param [in] pIpAddress Buffer containing IP4 network address of the local host
- @param [in] PortNumber Udp4 port number
- @param [in] DebugFlags Flags for debug messages
- @param [out] ppPort Buffer to receive new DT_PORT structure address
+ @param [in] pPort Address of the ::ESL_PORT structure.
+ @param [in] ErrnoValue errno value if test fails
- @retval EFI_SUCCESS - Socket successfully created
+ @retval EFI_SUCCESS The connection was successfully established.
+ @retval Others The connection attempt failed.
**/
EFI_STATUS
-EslUdpPortAllocate4 (
- IN DT_SOCKET * pSocket,
- IN DT_SERVICE * pService,
- IN EFI_HANDLE ChildHandle,
- IN CONST UINT8 * pIpAddress,
- IN UINT16 PortNumber,
- IN UINTN DebugFlags,
- OUT DT_PORT ** ppPort
+EslSocketBindTest (
+ IN ESL_PORT * pPort,
+ IN int ErrnoValue
);
/**
- Close a UDP4 port.
+ Copy a fragmented buffer into a destination buffer.
- This routine releases the resources allocated by
- ::UdpPortAllocate4().
-
- @param [in] pPort Address of the port structure.
+ This support routine copies a fragmented buffer to the caller specified buffer.
- @retval EFI_SUCCESS The port is closed
- @retval other Port close error
+ This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
-**/
-EFI_STATUS
-EslUdpPortClose4 (
- IN DT_PORT * pPort
- );
+ @param [in] FragmentCount Number of fragments in the table
-/**
- Start the close operation on a UDP4 port, state 1.
+ @param [in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure
- Closing a port goes through the following states:
- 1. Port close starting - Mark the port as closing and wait for transmission to complete
- 2. Port TX close done - Transmissions complete, close the port and abort the receives
- 3. Port RX close done - Receive operations complete, close the port
- 4. Port closed - Release the port resources
-
- @param [in] pPort Address of the port structure.
- @param [in] bCloseNow Set TRUE to abort active transfers
- @param [in] DebugFlags Flags for debug messages
+ @param [in] BufferLength Length of the the buffer
- @retval EFI_SUCCESS The port is closed, not normally returned
- @retval EFI_NOT_READY The port has started the closing process
- @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
- most likely the routine was called already.
+ @param [in] pBuffer Address of a buffer to receive the data.
+
+ @param [in] pDataLength Number of received data bytes in the buffer.
+
+ @return Returns the address of the next free byte in the buffer.
**/
-EFI_STATUS
-EslUdpPortCloseStart4 (
- IN DT_PORT * pPort,
- IN BOOLEAN bCloseNow,
- IN UINTN DebugFlags
+UINT8 *
+EslSocketCopyFragmentedBuffer (
+ IN UINT32 FragmentCount,
+ IN EFI_IP4_FRAGMENT_DATA * pFragmentTable,
+ IN size_t BufferLength,
+ IN UINT8 * pBuffer,
+ OUT size_t * pDataLength
);
/**
- Port close state 2
+ Free the ESL_IO_MGMT event and structure
- Continue the close operation after the transmission is complete.
+ This support routine walks the free list to close the event in
+ the ESL_IO_MGMT structure and remove the structure from the free
+ list.
- @param [in] pPort Address of the port structure.
+ See the \ref TransmitEngine section.
- @retval EFI_SUCCESS The port is closed, not normally returned
- @retval EFI_NOT_READY The port is still closing
- @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
- most likely the routine was called already.
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in] ppFreeQueue Address of the free queue head
+ @param [in] DebugFlags Flags for debug messages
+ @param [in] pEventName Zero terminated string containing the event name
+
+ @retval EFI_SUCCESS - The structures were properly initialized
**/
EFI_STATUS
-EslUdpPortCloseTxDone4 (
- IN DT_PORT * pPort
+EslSocketIoFree (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT ** ppFreeQueue,
+ IN UINTN DebugFlags,
+ IN CHAR8 * pEventName
);
/**
- Connect to a remote system via the network.
+ Initialize the ESL_IO_MGMT structures
- The ::UdpConnectStart4= routine sets the remote address for the connection.
+ This support routine initializes the ESL_IO_MGMT structure and
+ places them on to a free list.
- @param [in] pSocket Address of the socket structure.
+ This routine is called by the PortAllocate routines to prepare
+ the transmit engines. See the \ref TransmitEngine section.
- @param [in] pSockAddr Network address of the remote system.
-
- @param [in] SockAddrLength Length in bytes of the network address.
-
- @retval EFI_SUCCESS The connection was successfully established.
- @retval EFI_NOT_READY The connection is in progress, call this routine again.
- @retval Others The connection attempt failed.
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in, out] ppIo Address containing the first structure address. Upon
+ return this buffer contains the next structure address.
+ @param [in] TokenCount Number of structures to initialize
+ @param [in] ppFreeQueue Address of the free queue head
+ @param [in] DebugFlags Flags for debug messages
+ @param [in] pEventName Zero terminated string containing the event name
+ @param [in] pfnCompletion Completion routine address
- **/
+ @retval EFI_SUCCESS - The structures were properly initialized
+
+**/
EFI_STATUS
-EslUdpConnect4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
+EslSocketIoInit (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT ** ppIo,
+ IN UINTN TokenCount,
+ IN ESL_IO_MGMT ** ppFreeQueue,
+ IN UINTN DebugFlags,
+ IN CHAR8 * pEventName,
+ IN EFI_EVENT_NOTIFY pfnCompletion
);
/**
- Get the local socket address
+ Determine if the socket is configured
- @param [in] pSocket Address of the socket structure.
+ This support routine is called to determine if the socket if the
+ configuration call was made to the network layer. The following
+ routines call this routine to verify that they may be successful
+ in their operations:
+ <ul>
+ <li>::EslSocketGetLocalAddress</li>
+ <li>::EslSocketGetPeerAddress</li>
+ <li>::EslSocketPoll</li>
+ <li>::EslSocketReceive</li>
+ <li>::EslSocketTransmit</li>
+ </ul>
- @param [out] pAddress Network address to receive the local system address
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
- @param [in,out] pAddressLength Length of the local network address structure
-
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
+ @retval EFI_SUCCESS - The socket is configured
**/
EFI_STATUS
-EslUdpGetLocalAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+EslSocketIsConfigured (
+ IN ESL_SOCKET * pSocket
);
/**
- Get the remote socket address
-
- @param [in] pSocket Address of the socket structure.
+ Allocate a packet for a receive or transmit operation
- @param [out] pAddress Network address to receive the remote system address
+ This support routine is called by ::EslSocketRxStart and the
+ network specific TxBuffer routines to get buffer space for the
+ next operation.
- @param [in,out] pAddressLength Length of the remote network address structure
+ @param [in] ppPacket Address to receive the ::ESL_PACKET structure
+ @param [in] LengthInBytes Length of the packet structure
+ @param [in] ZeroBytes Length of packet to zero
+ @param [in] DebugFlags Flags for debug messages
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
+ @retval EFI_SUCCESS - The packet was allocated successfully
-**/
+ **/
EFI_STATUS
-EslUdpGetRemoteAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+EslSocketPacketAllocate (
+ IN ESL_PACKET ** ppPacket,
+ IN size_t LengthInBytes,
+ IN size_t ZeroBytes,
+ IN UINTN DebugFlags
);
/**
- Receive data from a network connection.
-
- To minimize the number of buffer copies, the ::UdpRxComplete4
- routine queues the UDP4 driver's buffer to a list of datagrams
- waiting to be received. The socket driver holds on to the
- buffers from the UDP4 driver until the application layer requests
- the data or the socket is closed.
+ Free a packet used for receive or transmit operation
- The application calls this routine in the socket layer to
- receive datagrams from one or more remote systems. This routine
- removes the next available datagram from the list of datagrams
- and copies the data from the UDP4 driver's buffer into the
- application's buffer. The UDP4 driver's buffer is then returned.
+ This support routine is called by the network specific Close
+ and TxComplete routines and during error cases in RxComplete
+ and TxBuffer. Note that the network layers typically place
+ receive packets on the ESL_SOCKET::pRxFree list for reuse.
- @param [in] pSocket Address of a DT_SOCKET structure
+ @param [in] pPacket Address of an ::ESL_PACKET structure
+ @param [in] DebugFlags Flags for debug messages
- @param [in] Flags Message control flags
+ @retval EFI_SUCCESS - The packet was allocated successfully
- @param [in] BufferLength Length of the the buffer
+ **/
+EFI_STATUS
+EslSocketPacketFree (
+ IN ESL_PACKET * pPacket,
+ IN UINTN DebugFlags
+ );
- @param [in] pBuffer Address of a buffer to receive the data.
+/**
+ Allocate and initialize a ESL_PORT structure.
- @param [in] pDataLength Number of received data bytes in the buffer.
+ This routine initializes an ::ESL_PORT structure for use by
+ the socket. This routine calls a routine via
+ ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
+ specific resources. The resources are released later by the
+ \ref PortCloseStateMachine.
- @param [out] pAddress Network address to receive the remote system address
+ This support routine is called by ::EslSocketBind and
+ ::EslTcp4ListenComplete to connect the socket with the
+ underlying network adapter to the socket.
- @param [in,out] pAddressLength Length of the remote network address structure
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
+ @param [in] pService Address of an ::ESL_SERVICE structure.
+ @param [in] ChildHandle TCP4 child handle
+ @param [in] pSockAddr Address of a sockaddr structure that contains the
+ connection point on the local machine. An IPv4 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv4 address restricts the connection to the
+ network stack supporting that address. Specifying zero
+ for the port causes the network layer to assign a port
+ number from the dynamic range. Specifying a specific
+ port number causes the network layer to use that port.
+ @param [in] bBindTest TRUE if EslSocketBindTest should be called
+ @param [in] DebugFlags Flags for debug messages
+ @param [out] ppPort Buffer to receive new ::ESL_PORT structure address
- @retval EFI_SUCCESS - Socket data successfully received
+ @retval EFI_SUCCESS - Socket successfully created
-**/
+ **/
EFI_STATUS
-EslUdpReceive4 (
- IN DT_SOCKET * pSocket,
- IN INT32 Flags,
- IN size_t BufferLength,
- IN UINT8 * pBuffer,
- OUT size_t * pDataLength,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+EslSocketPortAllocate (
+ IN ESL_SOCKET * pSocket,
+ IN ESL_SERVICE * pService,
+ IN EFI_HANDLE ChildHandle,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest,
+ IN UINTN DebugFlags,
+ OUT ESL_PORT ** ppPort
);
/**
- Cancel the receive operations
-
- @param [in] pSocket Address of a DT_SOCKET structure
+ Close a port.
+
+ This routine releases the resources allocated by ::EslSocketPortAllocate.
+ This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
+ specific resources.
+
+ This routine is called by:
+ <ul>
+ <li>::EslIp4PortAllocate - Port initialization failure</li>
+ <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
+ <li>::EslTcp4ConnectComplete - Connection failure and reducint the port list to a single port</li>
+ <li>::EslTcp4PortAllocate - Port initialization failure</li>
+ <li>::EslUdp4PortAllocate - Port initialization failure</li>
+ </ul>
+ See the \ref PortCloseStateMachine section.
- @retval EFI_SUCCESS - The cancel was successful
+ @param [in] pPort Address of an ::ESL_PORT structure.
- **/
+ @retval EFI_SUCCESS The port is closed
+ @retval other Port close error
+
+**/
EFI_STATUS
-EslUdpRxCancel4 (
- IN DT_SOCKET * pSocket
+EslSocketPortClose (
+ IN ESL_PORT * pPort
);
/**
- Process the receive completion
+ Process the port close completion event
- Keep the UDP4 driver's buffer and append it to the list of
- datagrams for the application to receive. The UDP4 driver's
- buffer will be returned by either ::UdpReceive4 or
- ::UdpPortCloseTxDone4.
+ This routine attempts to complete the port close operation.
- @param Event The receive completion event
+ This routine is called by the TCP layer upon completion of
+ the close operation.
+ See the \ref PortCloseStateMachine section.
- @param pPort The DT_PORT structure address
+ @param [in] Event The close completion event
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
**/
VOID
-EslUdpRxComplete4 (
+EslSocketPortCloseComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_PORT * pPort
);
/**
- Start a receive operation
+ Port close state 3
- @param [in] pPort Address of the DT_PORT structure.
+ This routine determines the state of the receive operations and
+ continues the close operation after the pending receive operations
+ are cancelled.
- **/
-VOID
-EslUdpRxStart4 (
- IN DT_PORT * pPort
+ This routine is called by
+ <ul>
+ <li>::EslIp4RxComplete</li>
+ <li>::EslSocketPortCloseComplete</li>
+ <li>::EslSocketPortCloseTxDone</li>
+ <li>::EslUdp4RxComplete</li>
+ </ul>
+ to determine the state of the receive operations.
+ See the \ref PortCloseStateMachine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @retval EFI_SUCCESS The port is closed
+ @retval EFI_NOT_READY The port is still closing
+ @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
+ most likely the routine was called already.
+
+**/
+EFI_STATUS
+EslSocketPortCloseRxDone (
+ IN ESL_PORT * pPort
);
/**
- Determine if the socket is configured.
+ Start the close operation on a port, state 1.
+ This routine marks the port as closed and initiates the \ref
+ PortCloseStateMachine. The first step is to allow the \ref
+ TransmitEngine to run down.
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @retval EFI_SUCCESS - The port is connected
- @retval EFI_NOT_STARTED - The port is not connected
+ This routine is called by ::EslSocketCloseStart to initiate the socket
+ network specific close operation on the socket.
- **/
- EFI_STATUS
- EslUdpSocketIsConfigured4 (
- IN DT_SOCKET * pSocket
+ @param [in] pPort Address of an ::ESL_PORT structure.
+ @param [in] bCloseNow Set TRUE to abort active transfers
+ @param [in] DebugFlags Flags for debug messages
+
+ @retval EFI_SUCCESS The port is closed, not normally returned
+ @retval EFI_NOT_READY The port has started the closing process
+ @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
+ most likely the routine was called already.
+
+**/
+EFI_STATUS
+EslSocketPortCloseStart (
+ IN ESL_PORT * pPort,
+ IN BOOLEAN bCloseNow,
+ IN UINTN DebugFlags
);
/**
- Process the transmit completion
+ Port close state 2
+
+ This routine determines the state of the transmit engine and
+ continue the close operation after the transmission is complete.
+ The next step is to stop the \ref ReceiveEngine.
+ See the \ref PortCloseStateMachine section.
+
+ This routine is called by ::EslSocketPortCloseStart to determine
+ if the transmission is complete.
- @param Event The normal transmit completion event
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @param pPort The DT_PORT structure address
+ @retval EFI_SUCCESS The port is closed, not normally returned
+ @retval EFI_NOT_READY The port is still closing
+ @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
+ most likely the routine was called already.
**/
-VOID
-EslUdpTxComplete4 (
- IN EFI_EVENT Event,
- IN DT_PORT * pPort
+EFI_STATUS
+EslSocketPortCloseTxDone (
+ IN ESL_PORT * pPort
);
/**
- Shutdown the UDP4 service.
+ Cancel the receive operations
- This routine undoes the work performed by ::UdpInitialize4.
+ This routine cancels a pending receive operation.
+ See the \ref ReceiveEngine section.
- @param [in] pService DT_SERVICE structure address
+ This routine is called by ::EslSocketShutdown when the socket
+ layer is being shutdown.
-**/
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+
+ **/
VOID
-EFIAPI
-EslUdpShutdown4 (
- IN DT_SERVICE * pService
+EslSocketRxCancel (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT * pIo
);
/**
- Buffer data for transmission over a network connection.
+ Process the receive completion
- This routine is called by the socket layer API to buffer
- data for transmission. The data is copied into a local buffer
- freeing the application buffer for reuse upon return. When
- necessary, this routine will start the transmit engine that
- performs the data transmission on the network connection. The
- transmit engine transmits the data a packet at a time over the
- network connection.
+ This routine queues the data in FIFO order in either the urgent
+ or normal data queues depending upon the type of data received.
+ See the \ref ReceiveEngine section.
- Transmission errors are returned during the next transmission or
- during the close operation. Only buffering errors are returned
- during the current transmission attempt.
+ This routine is called when some data is received by:
+ <ul>
+ <li>::EslIp4RxComplete</li>
+ <li>::EslTcp4RxComplete</li>
+ <li>::EslUdp4RxComplete</li>
+ </ul>
- @param [in] pSocket Address of a DT_SOCKET structure
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+ @param [in] Status Receive status
+ @param [in] LengthInBytes Length of the receive data
+ @param [in] bUrgent TRUE if urgent data is received and FALSE
+ for normal data.
- @param [in] Flags Message control flags
+**/
+VOID
+EslSocketRxComplete (
+ IN ESL_IO_MGMT * pIo,
+ IN EFI_STATUS Status,
+ IN UINTN LengthInBytes,
+ IN BOOLEAN bUrgent
+ );
- @param [in] BufferLength Length of the the buffer
+/**
+ Start a receive operation
- @param [in] pBuffer Address of a buffer to receive the data.
+ This routine posts a receive buffer to the network adapter.
+ See the \ref ReceiveEngine section.
- @param [in] pDataLength Number of received data bytes in the buffer.
+ This support routine is called by:
+ <ul>
+ <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
+ <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
+ <li>::EslIp4SocketIsConfigured to start the recevie engine for the new socket.</li>
+ <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
+ <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
+ <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
+ <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
+ <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
+ <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
+ </ul>
- @param [in] pAddress Network address of the remote system address
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @param [in] AddressLength Length of the remote network address structure
+ **/
+VOID
+EslSocketRxStart (
+ IN ESL_PORT * pPort
+ );
- @retval EFI_SUCCESS - Socket data successfully buffered
+/**
+ Complete the transmit operation
+
+ This support routine handles the transmit completion processing for
+ the various network layers. It frees the ::ESL_IO_MGMT structure
+ and and frees packet resources by calling ::EslSocketPacketFree.
+ Transmit errors are logged in ESL_SOCKET::TxError.
+ See the \ref TransmitEngine section.
+
+ This routine is called by:
+ <ul>
+ <li>::EslIp4TxComplete</li>
+ <li>::EslTcp4TxComplete</li>
+ <li>::EslTcp4TxOobComplete</li>
+ <li>::EslUdp4TxComplete</li>
+ </ul>
+
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+ @param [in] LengthInBytes Length of the data in bytes
+ @param [in] Status Transmit operation status
+ @param [in] pQueueType Zero terminated string describing queue type
+ @param [in] ppQueueHead Transmit queue head address
+ @param [in] ppQueueTail Transmit queue tail address
+ @param [in] ppActive Active transmit queue address
+ @param [in] ppFree Free transmit queue address
-**/
-EFI_STATUS
-EslUdpTxBuffer4 (
- IN DT_SOCKET * pSocket,
- IN int Flags,
- IN size_t BufferLength,
- IN CONST UINT8 * pBuffer,
- OUT size_t * pDataLength,
- IN const struct sockaddr * pAddress,
- IN socklen_t AddressLength
+ **/
+VOID
+EslSocketTxComplete (
+ IN ESL_IO_MGMT * pIo,
+ IN UINT32 LengthInBytes,
+ IN EFI_STATUS Status,
+ IN CONST CHAR8 * pQueueType,
+ IN ESL_PACKET ** ppQueueHead,
+ IN ESL_PACKET ** ppQueueTail,
+ IN ESL_IO_MGMT ** ppActive,
+ IN ESL_IO_MGMT ** ppFree
);
/**
Transmit data using a network connection.
- @param [in] pPort Address of a DT_PORT structure
+ This support routine starts a transmit operation on the
+ underlying network layer.
+
+ The network specific code calls this routine to start a
+ transmit operation. See the \ref TransmitEngine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in] ppQueueHead Transmit queue head address
+ @param [in] ppQueueTail Transmit queue tail address
+ @param [in] ppActive Active transmit queue address
+ @param [in] ppFree Free transmit queue address
**/
VOID
-EslUdpTxStart4 (
- IN DT_PORT * pPort
+EslSocketTxStart (
+ IN ESL_PORT * pPort,
+ IN ESL_PACKET ** ppQueueHead,
+ IN ESL_PACKET ** ppQueueTail,
+ IN ESL_IO_MGMT ** ppActive,
+ IN ESL_IO_MGMT ** ppFree
);
//------------------------------------------------------------------------------
diff --git a/StdLib/EfiSocketLib/Tcp4.c b/StdLib/EfiSocketLib/Tcp4.c
index b489608a5b..ec03b96bc1 100644
--- a/StdLib/EfiSocketLib/Tcp4.c
+++ b/StdLib/EfiSocketLib/Tcp4.c
@@ -10,19 +10,88 @@
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ \section ConnectionManagement Connection Management
+
+ The ::EslTcp4Listen routine initially places the SOCK_STREAM or
+ SOCK_SEQPACKET socket into a listen state. When a remote machine
+ makes a connection to the socket, the TCPv4 network layer calls
+ ::EslTcp4ListenComplete to complete the connection processing.
+ EslTcp4ListenComplete manages the connections by placing them in
+ FIFO order in a queue to be serviced by the application. When the
+ number of connections exceeds the backlog (ESL_SOCKET::MaxFifoDepth),
+ the new connection is closed. Eventually, the application indirectly
+ calls ::EslTcp4Accept to remove the next connection from the queue
+ and get the associated socket.
+
**/
#include "Socket.h"
/**
+ Attempt to connect to a remote TCP port
+
+ This routine starts the connection processing for a SOCK_STREAM
+ or SOCK_SEQPAKCET socket using the TCPv4 network layer. It
+ configures the local TCPv4 connection point and then attempts to
+ connect to a remote system. Upon completion, the
+ ::EslTcp4ConnectComplete routine gets called with the connection
+ status.
+
+ This routine is called by ::EslSocketConnect to initiate the TCPv4
+ network specific connect operations. The connection processing is
+ initiated by this routine and finished by ::EslTcp4ConnectComplete.
+ This pair of routines walks through the list of local TCPv4
+ connection points until a connection to the remote system is
+ made.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
+
+ @retval EFI_SUCCESS The connection was successfully established.
+ @retval EFI_NOT_READY The connection is in progress, call this routine again.
+ @retval Others The connection attempt failed.
+
+ **/
+EFI_STATUS
+EslTcp4ConnectStart (
+ IN ESL_SOCKET * pSocket
+ );
+
+
+/**
+ Process the connection attempt
+
+ A system has initiated a connection attempt with a socket in the
+ listen state. Attempt to complete the connection.
+
+ The TCPv4 layer calls this routine when a connection is made to
+ the socket in the listen state. See the
+ \ref ConnectionManagement section.
+
+ @param [in] Event The listen completion event
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+**/
+VOID
+EslTcp4ListenComplete (
+ IN EFI_EVENT Event,
+ IN ESL_PORT * pPort
+ );
+
+
+/**
Accept a network connection.
- The SocketAccept routine waits for a network connection to the socket.
- It is able to return the remote network address to the caller if
- requested.
+ This routine waits for a network connection to the socket and
+ returns the remote network address to the caller if requested.
+
+ This routine is called by ::EslSocketAccept to handle the TCPv4 protocol
+ specific accept operations for SOCK_STREAM and SOCK_SEQPACKET sockets.
+ See the \ref ConnectionManagement section.
- @param [in] pSocket Address of the socket structure.
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
@param [in] pSockAddr Address of a buffer to receive the remote
network address.
@@ -36,15 +105,15 @@
**/
EFI_STATUS
-EslTcpAccept4 (
- IN DT_SOCKET * pSocket,
+EslTcp4Accept (
+ IN ESL_SOCKET * pSocket,
IN struct sockaddr * pSockAddr,
IN OUT socklen_t * pSockAddrLength
)
{
- DT_PORT * pPort;
+ ESL_PORT * pPort;
struct sockaddr_in * pRemoteAddress;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_TCP4_CONTEXT * pTcp4;
UINT32 RemoteAddress;
EFI_STATUS Status;
@@ -102,302 +171,37 @@ EslTcpAccept4 (
/**
- Bind a name to a socket.
-
- The ::TcpBind4 routine connects a name to a TCP4 stack on the local machine.
-
- @param [in] pSocket Address of the socket structure.
-
- @param [in] pSockAddr Address of a sockaddr structure that contains the
- connection point on the local machine. An IPv4 address
- of INADDR_ANY specifies that the connection is made to
- all of the network stacks on the platform. Specifying a
- specific IPv4 address restricts the connection to the
- network stack supporting that address. Specifying zero
- for the port causes the network layer to assign a port
- number from the dynamic range. Specifying a specific
- port number causes the network layer to use that port.
-
- @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.
-
- @retval EFI_SUCCESS - Socket successfully created
-
- **/
-EFI_STATUS
-EslTcpBind4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
- )
-{
- EFI_HANDLE ChildHandle;
- DT_LAYER * pLayer;
- DT_PORT * pPort;
- DT_SERVICE * pService;
- CONST struct sockaddr_in * pIp4Address;
- EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;
- EFI_STATUS Status;
- EFI_STATUS TempStatus;
-
- DBG_ENTER ( );
-
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Assume success
- //
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
-
- //
- // Validate the address length
- //
- pIp4Address = (CONST struct sockaddr_in *) pSockAddr;
- if ( SockAddrLength >= ( sizeof ( *pIp4Address )
- - sizeof ( pIp4Address->sin_zero ))) {
-
- //
- // Walk the list of services
- //
- pLayer = &mEslLayer;
- pService = pLayer->pTcp4List;
- while ( NULL != pService ) {
- //
- // Create the TCP port
- //
- pTcp4Service = pService->pInterface;
- ChildHandle = NULL;
- Status = pTcp4Service->CreateChild ( pTcp4Service,
- &ChildHandle );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_BIND | DEBUG_POOL,
- "0x%08x: Tcp4 port handle created\r\n",
- ChildHandle ));
-
- //
- // Open the port
- //
- Status = EslTcpPortAllocate4 ( pSocket,
- pService,
- ChildHandle,
- (UINT8 *) &pIp4Address->sin_addr.s_addr,
- SwapBytes16 ( pIp4Address->sin_port ),
- DEBUG_BIND,
- &pPort );
- }
- else {
- DEBUG (( DEBUG_BIND | DEBUG_POOL,
- "ERROR - Failed to open Tcp4 port handle, Status: %r\r\n",
- Status ));
- ChildHandle = NULL;
- }
-
- //
- // Close the port if necessary
- //
- if (( EFI_ERROR ( Status )) && ( NULL != ChildHandle )) {
- TempStatus = pTcp4Service->DestroyChild ( pTcp4Service,
- ChildHandle );
- if ( !EFI_ERROR ( TempStatus )) {
- DEBUG (( DEBUG_BIND | DEBUG_POOL,
- "0x%08x: Tcp4 port handle destroyed\r\n",
- ChildHandle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,
- "ERROR - Failed to destroy the Tcp4 port handle 0x%08x, Status: %r\r\n",
- ChildHandle,
- TempStatus ));
- ASSERT ( EFI_SUCCESS == TempStatus );
- }
- }
-
- //
- // Set the next service
- //
- pService = pService->pNext;
- }
-
- //
- // Verify that at least one network connection was found
- //
- if ( NULL == pSocket->pPortList ) {
- DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
- "Socket address %d.%d.%d.%d (0x%08x) is not available!\r\n",
- ( pIp4Address->sin_addr.s_addr >> 24 ) & 0xff,
- ( pIp4Address->sin_addr.s_addr >> 16 ) & 0xff,
- ( pIp4Address->sin_addr.s_addr >> 8 ) & 0xff,
- pIp4Address->sin_addr.s_addr & 0xff,
- pIp4Address->sin_addr.s_addr ));
- pSocket->errno = EADDRNOTAVAIL;
- Status = EFI_INVALID_PARAMETER;
- }
- }
- else {
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid TCP4 address length: %d\r\n",
- SockAddrLength ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
- }
-
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Attempt to connect to a remote TCP port
-
- @param [in] pSocket Address of the socket structure.
-
- @retval EFI_SUCCESS The connection was successfully established.
- @retval EFI_NOT_READY The connection is in progress, call this routine again.
- @retval Others The connection attempt failed.
-
- **/
-EFI_STATUS
-EslTcpConnectAttempt4 (
- IN DT_SOCKET * pSocket
- )
-{
- DT_PORT * pPort;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_TCP4_PROTOCOL * pTcp4Protocol;
- EFI_STATUS Status;
+ Process the remote connection completion event.
- DBG_ENTER ( );
-
- //
- // Determine if any more local adapters are available
- //
- pPort = pSocket->pPortList;
- if ( NULL != pPort ) {
- //
- // Configure the port
- //
- pTcp4 = &pPort->Context.Tcp4;
- pTcp4->ConfigData.AccessPoint.ActiveFlag = TRUE;
- pTcp4->ConfigData.TimeToLive = 255;
- pTcp4Protocol = pTcp4->pProtocol;
- Status = pTcp4Protocol->Configure ( pTcp4Protocol,
- &pTcp4->ConfigData );
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
- Status ));
- switch ( Status ) {
- case EFI_ACCESS_DENIED:
- pSocket->errno = EACCES;
- break;
-
- default:
- case EFI_DEVICE_ERROR:
- pSocket->errno = EIO;
- break;
-
- case EFI_INVALID_PARAMETER:
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case EFI_NO_MAPPING:
- pSocket->errno = EAFNOSUPPORT;
- break;
-
- case EFI_OUT_OF_RESOURCES:
- pSocket->errno = ENOBUFS;
- break;
-
- case EFI_UNSUPPORTED:
- pSocket->errno = EOPNOTSUPP;
- break;
- }
- }
- else {
- DEBUG (( DEBUG_CONNECT,
- "0x%08x: Port configured\r\n",
- pPort ));
- pTcp4->bConfigured = TRUE;
-
- //
- // Attempt the connection to the remote system
- //
- Status = pTcp4Protocol->Connect ( pTcp4Protocol,
- &pTcp4->ConnectToken );
- if ( !EFI_ERROR ( Status )) {
- //
- // Connection in progress
- //
- pSocket->errno = EINPROGRESS;
- Status = EFI_NOT_READY;
- DEBUG (( DEBUG_CONNECT,
- "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",
- pPort,
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
- pTcp4->ConfigData.AccessPoint.RemotePort ));
- }
- else {
- //
- // Connection error
- //
- pSocket->errno = EINVAL;
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Port 0x%08x not connected, Status: %r\r\n",
- pPort,
- Status ));
- }
- }
- }
- else {
- //
- // No more local adapters available
- //
- pSocket->errno = ENETUNREACH;
- Status = EFI_NO_RESPONSE;
- }
-
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Process the remote connection attempt
-
- A connection attempt to a remote system has just completed when
- this routine is invoked. Release the port in the case of an
+ This routine handles the completion of a connection attempt. It
+ releases the port (TCPv4 adapter connection) in the case of an
error and start a connection attempt on the next port. If the
- connection attempt was successful, then release all of the other
- ports.
+ connection attempt was successful then this routine releases all
+ of the other ports.
- @param Event The connect completion event
+ This routine is called by the TCPv4 layer when a connect request
+ completes. It sets the ESL_SOCKET::bConnected flag to notify the
+ ::EslTcp4ConnectComplete routine that the connection is available.
+ The flag is set when the connection is established or no more ports
+ exist in the list. The connection status is passed via
+ ESL_SOCKET::ConnectStatus.
- @param pPort The DT_PORT structure address
+ @param [in] Event The connect completion event
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
**/
VOID
-EslTcpConnectComplete4 (
+EslTcp4ConnectComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_PORT * pPort
)
{
BOOLEAN bRemoveFirstPort;
BOOLEAN bRemovePorts;
- DT_PORT * pNextPort;
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_PORT * pNextPort;
+ ESL_SOCKET * pSocket;
+ ESL_TCP4_CONTEXT * pTcp4;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -422,10 +226,10 @@ EslTcpConnectComplete4 (
DEBUG (( DEBUG_CONNECT,
"0x%08x: Port connected to %d.%d.%d.%d:%d\r\n",
pPort,
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [0],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [1],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [2],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [3],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
pTcp4->ConfigData.AccessPoint.RemotePort ));
//
@@ -440,17 +244,17 @@ EslTcpConnectComplete4 (
DEBUG (( DEBUG_CONNECT,
"0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",
pPort,
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [0],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [1],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [2],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [3],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
pTcp4->ConfigData.AccessPoint.RemotePort,
Status ));
//
// Close the current port
//
- Status = EslTcpPortClose4 ( pPort );
+ Status = EslSocketPortClose ( pPort );
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_CONNECT,
"0x%08x: Port closed\r\n",
@@ -466,7 +270,7 @@ EslTcpConnectComplete4 (
//
// Try to connect using the next port
//
- Status = EslTcpConnectAttempt4 ( pSocket );
+ Status = EslTcp4ConnectStart ( pSocket );
if ( EFI_NOT_READY != Status ) {
pSocket->ConnectStatus = Status;
bRemoveFirstPort = TRUE;
@@ -490,7 +294,7 @@ EslTcpConnectComplete4 (
//
while ( NULL != pPort ) {
pNextPort = pPort->pLinkSocket;
- EslTcpPortClose4 ( pPort );
+ EslSocketPortClose ( pPort );
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_CONNECT,
"0x%08x: Port closed\r\n",
@@ -518,10 +322,16 @@ EslTcpConnectComplete4 (
/**
Poll for completion of the connection attempt.
- The ::TcpConnectPoll4 routine determines when the connection
- attempt transitions from being in process to being complete.
+ This routine polls the ESL_SOCKET::bConnected flag to determine
+ when the connection attempt is complete.
+
+ This routine is called from ::EslSocketConnect to determine when
+ the connection is complete. The ESL_SOCKET::bConnected flag is
+ set by ::EslTcp4ConnectComplete when the TCPv4 layer establishes
+ a connection or runs out of local network adapters. This routine
+ gets the connection status from ESL_SOCKET::ConnectStatus.
- @param [in] pSocket Address of the socket structure.
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
@retval EFI_SUCCESS The connection was successfully established.
@retval EFI_NOT_READY The connection is in progress, call this routine again.
@@ -529,8 +339,8 @@ EslTcpConnectComplete4 (
**/
EFI_STATUS
-EslTcpConnectPoll4 (
- IN DT_SOCKET * pSocket
+EslTcp4ConnectPoll (
+ IN ESL_SOCKET * pSocket
)
{
EFI_STATUS Status;
@@ -612,292 +422,165 @@ EslTcpConnectPoll4 (
/**
- Connect to a remote system via the network.
+ Attempt to connect to a remote TCP port
- The ::TcpConnectStart4= routine starts the connection processing
- for a TCP4 port.
+ This routine starts the connection processing for a SOCK_STREAM
+ or SOCK_SEQPAKCET socket using the TCPv4 network layer. It
+ configures the local TCPv4 connection point and then attempts to
+ connect to a remote system. Upon completion, the
+ ::EslTcp4ConnectComplete routine gets called with the connection
+ status.
- @param [in] pSocket Address of the socket structure.
+ This routine is called by ::EslSocketConnect to initiate the TCPv4
+ network specific connect operations. The connection processing is
+ initiated by this routine and finished by ::EslTcp4ConnectComplete.
+ This pair of routines walks through the list of local TCPv4
+ connection points until a connection to the remote system is
+ made.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
- @param [in] pSockAddr Network address of the remote system.
-
- @param [in] SockAddrLength Length in bytes of the network address.
-
@retval EFI_SUCCESS The connection was successfully established.
@retval EFI_NOT_READY The connection is in progress, call this routine again.
@retval Others The connection attempt failed.
**/
EFI_STATUS
-EslTcpConnectStart4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
+EslTcp4ConnectStart (
+ IN ESL_SOCKET * pSocket
)
{
- struct sockaddr_in LocalAddress;
- DT_PORT * pPort;
- DT_TCP4_CONTEXT * pTcp4;
- CONST struct sockaddr_in * pIp4Address;
+ ESL_PORT * pPort;
+ ESL_TCP4_CONTEXT * pTcp4;
+ EFI_TCP4_PROTOCOL * pTcp4Protocol;
EFI_STATUS Status;
DBG_ENTER ( );
-
+
//
- // Validate the address length
+ // Determine if any more local adapters are available
//
- Status = EFI_SUCCESS;
- pIp4Address = (CONST struct sockaddr_in *) pSockAddr;
- if ( SockAddrLength >= ( sizeof ( *pIp4Address )
- - sizeof ( pIp4Address->sin_zero ))) {
+ pPort = pSocket->pPortList;
+ if ( NULL != pPort ) {
//
- // Determine if BIND was already called
+ // Configure the port
//
- if ( NULL == pSocket->pPortList ) {
- //
- // Allow any local port
- //
- ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
- LocalAddress.sin_len = sizeof ( LocalAddress );
- LocalAddress.sin_family = AF_INET;
- Status = EslSocketBind ( &pSocket->SocketProtocol,
- (struct sockaddr *)&LocalAddress,
- LocalAddress.sin_len,
- &pSocket->errno );
+ pTcp4 = &pPort->Context.Tcp4;
+ pTcp4->ConfigData.AccessPoint.ActiveFlag = TRUE;
+ pTcp4->ConfigData.TimeToLive = 255;
+ pTcp4Protocol = pPort->pProtocol.TCPv4;
+ Status = pTcp4Protocol->Configure ( pTcp4Protocol,
+ &pTcp4->ConfigData );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
+ Status ));
+ switch ( Status ) {
+ case EFI_ACCESS_DENIED:
+ pSocket->errno = EACCES;
+ break;
+
+ default:
+ case EFI_DEVICE_ERROR:
+ pSocket->errno = EIO;
+ break;
+
+ case EFI_INVALID_PARAMETER:
+ pSocket->errno = EADDRNOTAVAIL;
+ break;
+
+ case EFI_NO_MAPPING:
+ pSocket->errno = EAFNOSUPPORT;
+ break;
+
+ case EFI_OUT_OF_RESOURCES:
+ pSocket->errno = ENOBUFS;
+ break;
+
+ case EFI_UNSUPPORTED:
+ pSocket->errno = EOPNOTSUPP;
+ break;
+ }
}
- if ( NULL != pSocket->pPortList ) {
+ else {
+ DEBUG (( DEBUG_CONNECT,
+ "0x%08x: Port configured\r\n",
+ pPort ));
+ pPort->bConfigured = TRUE;
+
//
- // Walk the list of ports
+ // Attempt the connection to the remote system
//
- pPort = pSocket->pPortList;
- while ( NULL != pPort ) {
+ Status = pTcp4Protocol->Connect ( pTcp4Protocol,
+ &pTcp4->ConnectToken );
+ if ( !EFI_ERROR ( Status )) {
//
- // Set the remote address
+ // Connection in progress
//
- pTcp4 = &pPort->Context.Tcp4;
- *(UINT32 *)&pTcp4->ConfigData.AccessPoint.RemoteAddress = pIp4Address->sin_addr.s_addr;
- pTcp4->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pIp4Address->sin_port );
-
+ pSocket->errno = EINPROGRESS;
+ Status = EFI_NOT_READY;
+ DEBUG (( DEBUG_CONNECT,
+ "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",
+ pPort,
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
+ pTcp4->ConfigData.AccessPoint.RemotePort ));
+ }
+ else {
//
- // Set the next port
+ // Connection error
//
- pPort = pPort->pLinkSocket;
- }
-
- //
- // Attempt a connection using the first adapter
- //
- Status = EslTcpConnectAttempt4 ( pSocket );
- }
- }
- else {
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid TCP4 address length: %d\r\n",
- SockAddrLength ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
- }
-
- //
- // Return the initialization status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Initialize the TCP4 service.
-
- This routine initializes the TCP4 service after its service binding
- protocol was located on a controller.
-
- @param [in] pService DT_SERVICE structure address
-
- @retval EFI_SUCCESS The service was properly initialized
- @retval other A failure occurred during the service initialization
-
-**/
-EFI_STATUS
-EFIAPI
-EslTcpInitialize4 (
- IN DT_SERVICE * pService
- )
-{
- DT_LAYER * pLayer;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Identify the service
- //
- pService->NetworkType = NETWORK_TYPE_TCP4;
-
- //
- // Connect this service to the service list
- //
- pLayer = &mEslLayer;
- pService->pNext = pLayer->pTcp4List;
- pLayer->pTcp4List = pService;
-
- //
- // Assume the list is empty
- //
- Status = EFI_SUCCESS;
-
- //
- // Return the initialization status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Get the local socket address
-
- @param [in] pSocket Address of the socket structure.
-
- @param [out] pAddress Network address to receive the local system address
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Port 0x%08x not connected, Status: %r\r\n",
+ pPort,
+ Status ));
+ //
+ // Determine the errno value
+ //
+ switch ( Status ) {
+ default:
+ pSocket->errno = EIO;
+ break;
- @param [in,out] pAddressLength Length of the local network address structure
+ case EFI_OUT_OF_RESOURCES:
+ pSocket->errno = ENOBUFS;
+ break;
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
+ case EFI_TIMEOUT:
+ pSocket->errno = ETIMEDOUT;
+ break;
-**/
-EFI_STATUS
-EslTcpGetLocalAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
- )
-{
- socklen_t LengthInBytes;
- DT_PORT * pPort;
- struct sockaddr_in * pLocalAddress;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_STATUS Status;
+ case EFI_NETWORK_UNREACHABLE:
+ pSocket->errno = ENETDOWN;
+ break;
- DBG_ENTER ( );
+ case EFI_HOST_UNREACHABLE:
+ pSocket->errno = EHOSTUNREACH;
+ break;
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
+ case EFI_PORT_UNREACHABLE:
+ case EFI_PROTOCOL_UNREACHABLE:
+ case EFI_CONNECTION_REFUSED:
+ pSocket->errno = ECONNREFUSED;
+ break;
- //
- // Verify that there is just a single connection
- //
- pPort = pSocket->pPortList;
- if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
- //
- // Verify the address length
- //
- LengthInBytes = sizeof ( struct sockaddr_in );
- if ( LengthInBytes <= * pAddressLength ) {
- //
- // Return the local address
- //
- pTcp4 = &pPort->Context.Tcp4;
- pLocalAddress = (struct sockaddr_in *)pAddress;
- ZeroMem ( pLocalAddress, LengthInBytes );
- pLocalAddress->sin_family = AF_INET;
- pLocalAddress->sin_len = (uint8_t)LengthInBytes;
- pLocalAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.StationPort );
- CopyMem ( &pLocalAddress->sin_addr,
- &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],
- sizeof ( pLocalAddress->sin_addr ));
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
- }
- else {
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
+ case EFI_CONNECTION_RESET:
+ pSocket->errno = ECONNRESET;
+ break;
+ }
+ }
}
}
else {
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
- }
-
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Get the remote socket address
-
- @param [in] pSocket Address of the socket structure.
-
- @param [out] pAddress Network address to receive the remote system address
-
- @param [in,out] pAddressLength Length of the remote network address structure
-
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
-
-**/
-EFI_STATUS
-EslTcpGetRemoteAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
- )
-{
- socklen_t LengthInBytes;
- DT_PORT * pPort;
- struct sockaddr_in * pRemoteAddress;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Verify that there is just a single connection
- //
- pPort = pSocket->pPortList;
- if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
//
- // Verify the address length
+ // No more local adapters available
//
- LengthInBytes = sizeof ( struct sockaddr_in );
- if ( LengthInBytes <= * pAddressLength ) {
- //
- // Return the local address
- //
- pTcp4 = &pPort->Context.Tcp4;
- pRemoteAddress = (struct sockaddr_in *)pAddress;
- ZeroMem ( pRemoteAddress, LengthInBytes );
- pRemoteAddress->sin_family = AF_INET;
- pRemoteAddress->sin_len = (uint8_t)LengthInBytes;
- pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
- CopyMem ( &pRemoteAddress->sin_addr,
- &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
- sizeof ( pRemoteAddress->sin_addr ));
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
- }
- else {
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
- }
- }
- else {
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
+ pSocket->errno = ENETUNREACH;
+ Status = EFI_NO_RESPONSE;
}
-
+
//
// Return the operation status
//
@@ -909,27 +592,27 @@ EslTcpGetRemoteAddress4 (
/**
Establish the known port to listen for network connections.
- The ::Tcp4Listen routine places the port into a state that enables connection
- attempts. Connections are placed into FIFO order in a queue to be serviced
- by the application. The application calls the ::Tcp4Accept routine to remove
- the next connection from the queue and get the associated socket. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>
- documentation for the listen routine is available online for reference.
+ This routine places the port into a state that enables connection
+ attempts.
+
+ This routine is called by ::EslSocketListen to handle the network
+ specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET
+ sockets. See the \ref ConnectionManagement section.
- @param [in] pSocket Address of the socket structure.
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
@retval EFI_SUCCESS - Socket successfully created
@retval Other - Failed to enable the socket for listen
**/
EFI_STATUS
-EslTcpListen4 (
- IN DT_SOCKET * pSocket
+EslTcp4Listen (
+ IN ESL_SOCKET * pSocket
)
{
- DT_PORT * pNextPort;
- DT_PORT * pPort;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_PORT * pNextPort;
+ ESL_PORT * pPort;
+ ESL_TCP4_CONTEXT * pTcp4;
EFI_TCP4_PROTOCOL * pTcp4Protocol;
EFI_STATUS Status;
@@ -970,7 +653,7 @@ EslTcpListen4 (
pTcp4 = &pPort->Context.Tcp4;
Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslTcpListenComplete4,
+ (EFI_EVENT_NOTIFY)EslTcp4ListenComplete,
pPort,
&pTcp4->ListenToken.CompletionToken.Event );
if ( EFI_ERROR ( Status )) {
@@ -987,7 +670,7 @@ EslTcpListen4 (
//
// Configure the port
//
- pTcp4Protocol = pTcp4->pProtocol;
+ pTcp4Protocol = pPort->pProtocol.TCPv4;
Status = pTcp4Protocol->Configure ( pTcp4Protocol,
&pTcp4->ConfigData );
if ( EFI_ERROR ( Status )) {
@@ -1025,7 +708,7 @@ EslTcpListen4 (
DEBUG (( DEBUG_LISTEN,
"0x%08x: Port configured\r\n",
pPort ));
- pTcp4->bConfigured = TRUE;
+ pPort->bConfigured = TRUE;
//
// Start the listen operation on the port
@@ -1078,9 +761,8 @@ EslTcpListen4 (
//
// Close the port upon error
//
- if ( EFI_ERROR ( Status ))
- {
- EslTcpPortCloseStart4 ( pPort, TRUE, DEBUG_LISTEN );
+ if ( EFI_ERROR ( Status )) {
+ EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );
}
//
@@ -1132,30 +814,36 @@ EslTcpListen4 (
A system has initiated a connection attempt with a socket in the
listen state. Attempt to complete the connection.
- @param Event The listen completion event
+ The TCPv4 layer calls this routine when a connection is made to
+ the socket in the listen state. See the
+ \ref ConnectionManagement section.
+
+ @param [in] Event The listen completion event
- @param pPort The DT_PORT structure address
+ @param [in] pPort Address of an ::ESL_PORT structure.
**/
VOID
-EslTcpListenComplete4 (
+EslTcp4ListenComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_PORT * pPort
)
{
EFI_HANDLE ChildHandle;
+ struct sockaddr_in LocalAddress;
EFI_TCP4_CONFIG_DATA * pConfigData;
- DT_LAYER * pLayer;
- DT_PORT * pNewPort;
- DT_SOCKET * pNewSocket;
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_LAYER * pLayer;
+ ESL_PORT * pNewPort;
+ ESL_SOCKET * pNewSocket;
+ ESL_SOCKET * pSocket;
+ ESL_TCP4_CONTEXT * pTcp4;
EFI_TCP4_PROTOCOL * pTcp4Protocol;
EFI_STATUS Status;
EFI_HANDLE TcpPortHandle;
EFI_STATUS TempStatus;
DBG_ENTER ( );
+ VERIFY_AT_TPL ( TPL_SOCKETS );
//
// Assume success
@@ -1181,26 +869,36 @@ EslTcpListenComplete4 (
//
// Clone the socket parameters
//
+ pNewSocket->pApi = pSocket->pApi;
pNewSocket->Domain = pSocket->Domain;
pNewSocket->Protocol = pSocket->Protocol;
pNewSocket->Type = pSocket->Type;
//
- // Allocate a port for this connection
+ // Build the local address
//
pTcp4 = &pPort->Context.Tcp4;
- Status = EslTcpPortAllocate4 ( pNewSocket,
- pPort->pService,
- TcpPortHandle,
- &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],
- 0,
- DEBUG_CONNECTION,
- &pNewPort );
+ LocalAddress.sin_len = (uint8_t)pNewSocket->pApi->MinimumAddressLength;
+ LocalAddress.sin_family = AF_INET;
+ LocalAddress.sin_port = 0;
+ LocalAddress.sin_addr.s_addr = *(UINT32 *)&pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0];
+
+ //
+ // Allocate a port for this connection
+ // Note in this instance Configure may not be called with NULL!
+ //
+ Status = EslSocketPortAllocate ( pNewSocket,
+ pPort->pService,
+ TcpPortHandle,
+ (struct sockaddr *)&LocalAddress,
+ FALSE,
+ DEBUG_CONNECTION,
+ &pNewPort );
if ( !EFI_ERROR ( Status )) {
//
// Restart the listen operation on the port
//
- pTcp4Protocol = pTcp4->pProtocol;
+ pTcp4Protocol = pPort->pProtocol.TCPv4;
Status = pTcp4Protocol->Accept ( pTcp4Protocol,
&pTcp4->ListenToken );
@@ -1209,7 +907,6 @@ EslTcpListenComplete4 (
//
TcpPortHandle = NULL;
pTcp4 = &pNewPort->Context.Tcp4;
- pTcp4->bConfigured = TRUE;
//
// Check for an accept call error
@@ -1218,9 +915,10 @@ EslTcpListenComplete4 (
//
// Get the port configuration
//
+ pNewPort->bConfigured = TRUE;
pConfigData = &pTcp4->ConfigData;
pConfigData->ControlOption = &pTcp4->Option;
- pTcp4Protocol = pTcp4->pProtocol;
+ pTcp4Protocol = pNewPort->pProtocol.TCPv4;
Status = pTcp4Protocol->GetModeData ( pTcp4Protocol,
NULL,
pConfigData,
@@ -1276,7 +974,7 @@ EslTcpListenComplete4 (
//
// Start the receive operation
//
- EslTcpRxStart4 ( pNewPort );
+ EslSocketRxStart ( pNewPort );
}
else {
DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO,
@@ -1297,7 +995,7 @@ EslTcpListenComplete4 (
//
// Close the listening port
//
- EslTcpPortCloseStart4 ( pPort, TRUE, DEBUG_LISTEN );
+ EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );
}
}
@@ -1343,137 +1041,228 @@ EslTcpListenComplete4 (
/**
- Allocate and initialize a DT_PORT structure.
+ Get the local socket address.
- @param [in] pSocket Address of the socket structure.
- @param [in] pService Address of the DT_SERVICE structure.
- @param [in] ChildHandle TCP4 child handle
- @param [in] pIpAddress Buffer containing IP4 network address of the local host
- @param [in] PortNumber Tcp4 port number
- @param [in] DebugFlags Flags for debug messages
- @param [out] ppPort Buffer to receive new DT_PORT structure address
+ This routine returns the IPv4 address and TCP port number associated
+ with the local socket.
- @retval EFI_SUCCESS - Socket successfully created
+ This routine is called by ::EslSocketGetLocalAddress to determine the
+ network address for the SOCK_STREAM or SOCK_SEQPACKET socket.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [out] pSockAddr Network address to receive the local system address
+
+**/
+VOID
+EslTcp4LocalAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pSockAddr
+ )
+{
+ struct sockaddr_in * pLocalAddress;
+ ESL_TCP4_CONTEXT * pTcp4;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the local address
+ //
+ pTcp4 = &pPort->Context.Tcp4;
+ pLocalAddress = (struct sockaddr_in *)pSockAddr;
+ pLocalAddress->sin_family = AF_INET;
+ pLocalAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.StationPort );
+ CopyMem ( &pLocalAddress->sin_addr,
+ &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],
+ sizeof ( pLocalAddress->sin_addr ));
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Set the local port address.
+
+ This routine sets the local port address.
+
+ This support routine is called by ::EslSocketPortAllocate.
+
+ @param [in] pPort Address of an ESL_PORT structure
+ @param [in] pSockAddr Address of a sockaddr structure that contains the
+ connection point on the local machine. An IPv4 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv4 address restricts the connection to the
+ network stack supporting that address. Specifying zero
+ for the port causes the network layer to assign a port
+ number from the dynamic range. Specifying a specific
+ port number causes the network layer to use that port.
+
+ @param [in] bBindTest TRUE = run bind testing
+
+ @retval EFI_SUCCESS The operation was successful
**/
EFI_STATUS
-EslTcpPortAllocate4 (
- IN DT_SOCKET * pSocket,
- IN DT_SERVICE * pService,
- IN EFI_HANDLE ChildHandle,
- IN CONST UINT8 * pIpAddress,
- IN UINT16 PortNumber,
- IN UINTN DebugFlags,
- OUT DT_PORT ** ppPort
+EslTcp4LocalAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest
)
{
- UINTN LengthInBytes;
EFI_TCP4_ACCESS_POINT * pAccessPoint;
- DT_LAYER * pLayer;
- DT_PORT * pPort;
- DT_TCP4_CONTEXT * pTcp4;
+ CONST struct sockaddr_in * pIpAddress;
+ CONST UINT8 * pIpv4Address;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Use for/break instead of goto
- for ( ; ; ) {
+ // Validate the address
+ //
+ pIpAddress = (struct sockaddr_in *)pSockAddr;
+ if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {
//
- // Allocate a port structure
+ // The local address must not be the broadcast address
//
- pLayer = &mEslLayer;
- LengthInBytes = sizeof ( *pPort );
- Status = gBS->AllocatePool ( EfiRuntimeServicesData,
- LengthInBytes,
- (VOID **)&pPort );
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,
- "ERROR - Failed to allocate the port structure, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- pPort = NULL;
- break;
- }
- DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
- "0x%08x: Allocate pPort, %d bytes\r\n",
- pPort,
- LengthInBytes ));
-
+ Status = EFI_INVALID_PARAMETER;
+ pPort->pSocket->errno = EADDRNOTAVAIL;
+ }
+ else {
//
- // Initialize the port
+ // Set the local address
//
- ZeroMem ( pPort, LengthInBytes );
- pPort->Signature = PORT_SIGNATURE;
- pPort->pService = pService;
- pPort->pSocket = pSocket;
- pPort->pfnCloseStart = EslTcpPortCloseStart4;
- pPort->DebugFlags = DebugFlags;
+ pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;
+ pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;
+ pAccessPoint->StationAddress.Addr[0] = pIpv4Address[0];
+ pAccessPoint->StationAddress.Addr[1] = pIpv4Address[1];
+ pAccessPoint->StationAddress.Addr[2] = pIpv4Address[2];
+ pAccessPoint->StationAddress.Addr[3] = pIpv4Address[3];
//
- // Allocate the receive event
+ // Determine if the default address is used
//
- pTcp4 = &pPort->Context.Tcp4;
- Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
- TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslTcpRxComplete4,
- pPort,
- &pTcp4->RxToken.CompletionToken.Event);
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to create the receive event, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- break;
- }
- DEBUG (( DEBUG_RX | DEBUG_POOL,
- "0x%08x: Created receive event\r\n",
- pTcp4->RxToken.CompletionToken.Event ));
-
+ pAccessPoint->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );
+
//
- // Allocate the urgent transmit event
+ // Set the subnet mask
//
- Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
- TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslTcpTxOobComplete4,
- pPort,
- &pTcp4->TxOobToken.CompletionToken.Event);
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to create the urgent transmit event, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- break;
+ if ( pAccessPoint->UseDefaultAddress ) {
+ pAccessPoint->SubnetMask.Addr[0] = 0;
+ pAccessPoint->SubnetMask.Addr[1] = 0;
+ pAccessPoint->SubnetMask.Addr[2] = 0;
+ pAccessPoint->SubnetMask.Addr[3] = 0;
+ }
+ else {
+ pAccessPoint->SubnetMask.Addr[0] = 0xff;
+ pAccessPoint->SubnetMask.Addr[1] = 0xff;
+ pAccessPoint->SubnetMask.Addr[2] = 0xff;
+ pAccessPoint->SubnetMask.Addr[3] = 0xff;
}
- DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
- "0x%08x: Created urgent transmit event\r\n",
- pTcp4->TxOobToken.CompletionToken.Event ));
//
- // Allocate the normal transmit event
+ // Validate the IP address
//
- Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
- TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslTcpTxComplete4,
- pPort,
- &pTcp4->TxToken.CompletionToken.Event);
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to create the normal transmit event, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- break;
+ pAccessPoint->StationPort = 0;
+ Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )
+ : EFI_SUCCESS;
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Set the port number
+ //
+ pAccessPoint->StationPort = SwapBytes16 ( pIpAddress->sin_port );
+
+ //
+ // Display the local address
+ //
+ DEBUG (( DEBUG_BIND,
+ "0x%08x: Port, Local TCP4 Address: %d.%d.%d.%d:%d\r\n",
+ pPort,
+ pAccessPoint->StationAddress.Addr[0],
+ pAccessPoint->StationAddress.Addr[1],
+ pAccessPoint->StationAddress.Addr[2],
+ pAccessPoint->StationAddress.Addr[3],
+ pAccessPoint->StationPort ));
}
- DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
- "0x%08x: Created normal transmit event\r\n",
- pTcp4->TxToken.CompletionToken.Event ));
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Free a receive packet
+
+ This routine performs the network specific operations necessary
+ to free a receive packet.
+
+ This routine is called by ::EslSocketPortCloseTxDone to free a
+ receive packet.
+
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
+ @param [in, out] pRxBytes Address of the count of RX bytes
+
+**/
+VOID
+EslTcp4PacketFree (
+ IN ESL_PACKET * pPacket,
+ IN OUT size_t * pRxBytes
+ )
+{
+ DBG_ENTER ( );
+ //
+ // Account for the receive bytes
+ //
+ *pRxBytes -= pPacket->Op.Tcp4Rx.RxData.DataLength;
+ DBG_EXIT ( );
+}
+
+
+/**
+ Initialize the network specific portions of an ::ESL_PORT structure.
+
+ This routine initializes the network specific portions of an
+ ::ESL_PORT structure for use by the socket.
+
+ This support routine is called by ::EslSocketPortAllocate
+ to connect the socket with the underlying network adapter
+ running the TCPv4 protocol.
+
+ @param [in] pPort Address of an ESL_PORT structure
+ @param [in] DebugFlags Flags for debug messages
+
+ @retval EFI_SUCCESS - Socket successfully created
+
+ **/
+EFI_STATUS
+EslTcp4PortAllocate (
+ IN ESL_PORT * pPort,
+ IN UINTN DebugFlags
+ )
+{
+ EFI_TCP4_ACCESS_POINT * pAccessPoint;
+ ESL_SOCKET * pSocket;
+ ESL_TCP4_CONTEXT * pTcp4;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Use for/break instead of goto
+ for ( ; ; ) {
//
// Allocate the close event
//
+ pSocket = pPort->pSocket;
+ pTcp4 = &pPort->Context.Tcp4;
Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslTcpPortCloseComplete4,
+ (EFI_EVENT_NOTIFY)EslSocketPortCloseComplete,
pPort,
&pTcp4->CloseToken.CompletionToken.Event);
if ( EFI_ERROR ( Status )) {
@@ -1492,7 +1281,7 @@ EslTcpPortAllocate4 (
//
Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslTcpConnectComplete4,
+ (EFI_EVENT_NOTIFY)EslTcp4ConnectComplete,
pPort,
&pTcp4->ConnectToken.CompletionToken.Event);
if ( EFI_ERROR ( Status )) {
@@ -1507,90 +1296,30 @@ EslTcpPortAllocate4 (
pTcp4->ConnectToken.CompletionToken.Event ));
//
- // Open the port protocol
- //
- Status = gBS->OpenProtocol (
- ChildHandle,
- &gEfiTcp4ProtocolGuid,
- (VOID **) &pTcp4->pProtocol,
- pLayer->ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to open gEfiTcp4ProtocolGuid on controller 0x%08x\r\n",
- pTcp4->Handle ));
- pSocket->errno = EEXIST;
- break;
- }
- DEBUG (( DebugFlags,
- "0x%08x: gEfiTcp4ProtocolGuid opened on controller 0x%08x\r\n",
- pTcp4->pProtocol,
- ChildHandle ));
-
- //
- // Set the port address
- //
- pTcp4->Handle = ChildHandle;
- pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;
- pAccessPoint->StationPort = PortNumber;
- if (( 0 == pIpAddress[0])
- && ( 0 == pIpAddress[1])
- && ( 0 == pIpAddress[2])
- && ( 0 == pIpAddress[3])) {
- pAccessPoint->UseDefaultAddress = TRUE;
- }
- else {
- pAccessPoint->StationAddress.Addr[0] = pIpAddress[0];
- pAccessPoint->StationAddress.Addr[1] = pIpAddress[1];
- pAccessPoint->StationAddress.Addr[2] = pIpAddress[2];
- pAccessPoint->StationAddress.Addr[3] = pIpAddress[3];
- pAccessPoint->SubnetMask.Addr[0] = 0xff;
- pAccessPoint->SubnetMask.Addr[1] = 0xff;
- pAccessPoint->SubnetMask.Addr[2] = 0xff;
- pAccessPoint->SubnetMask.Addr[3] = 0xff;
- }
- pAccessPoint->ActiveFlag = FALSE;
- pTcp4->ConfigData.TimeToLive = 255;
-
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Add this port to the socket
+ // Initialize the port
//
- pPort->pLinkSocket = pSocket->pPortList;
- pSocket->pPortList = pPort;
- DEBUG (( DebugFlags,
- "0x%08x: Socket adding port: 0x%08x\r\n",
- pSocket,
- pPort ));
+ pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Tcp4Tx.TxData );
+ pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Tx.CompletionToken.Event );
+ pSocket->TxTokenOffset = OFFSET_OF ( EFI_TCP4_IO_TOKEN, Packet.TxData );
//
- // Add this port to the service
+ // Save the cancel, receive and transmit addresses
+ // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
//
- pPort->pLinkService = pService->pPortList;
- pService->pPortList = pPort;
+ pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.TCPv4->Configure;
+ pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Receive;
+ pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Transmit;
//
- // Return the port
+ // Set the configuration flags
//
- *ppPort = pPort;
+ pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;
+ pAccessPoint->ActiveFlag = FALSE;
+ pTcp4->ConfigData.TimeToLive = 255;
break;
}
//
- // Clean up after the error if necessary
- //
- if (( EFI_ERROR ( Status )) && ( NULL != pPort )) {
- //
- // Close the port
- //
- EslTcpPortClose4 ( pPort );
- }
- //
// Return the operation status
//
DBG_EXIT_STATUS ( Status );
@@ -1601,127 +1330,35 @@ EslTcpPortAllocate4 (
/**
Close a TCP4 port.
- This routine releases the resources allocated by
- ::TcpPortAllocate4().
+ This routine releases the network specific resources allocated by
+ ::EslTcp4PortAllocate.
+
+ This routine is called by ::EslSocketPortClose.
+ See the \ref PortCloseStateMachine section.
- @param [in] pPort Address of the port structure.
+ @param [in] pPort Address of an ::ESL_PORT structure.
@retval EFI_SUCCESS The port is closed
@retval other Port close error
**/
EFI_STATUS
-EslTcpPortClose4 (
- IN DT_PORT * pPort
+EslTcp4PortClose (
+ IN ESL_PORT * pPort
)
{
UINTN DebugFlags;
- DT_LAYER * pLayer;
- DT_PACKET * pPacket;
- DT_PORT * pPreviousPort;
- DT_SERVICE * pService;
- DT_SOCKET * pSocket;
- EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_TCP4_CONTEXT * pTcp4;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
// Locate the port in the socket list
//
Status = EFI_SUCCESS;
- pLayer = &mEslLayer;
DebugFlags = pPort->DebugFlags;
- pSocket = pPort->pSocket;
- pPreviousPort = pSocket->pPortList;
- if ( pPreviousPort == pPort ) {
- //
- // Remove this port from the head of the socket list
- //
- pSocket->pPortList = pPort->pLinkSocket;
- }
- else {
- //
- // Locate the port in the middle of the socket list
- //
- while (( NULL != pPreviousPort )
- && ( pPreviousPort->pLinkSocket != pPort )) {
- pPreviousPort = pPreviousPort->pLinkSocket;
- }
- if ( NULL != pPreviousPort ) {
- //
- // Remove the port from the middle of the socket list
- //
- pPreviousPort->pLinkSocket = pPort->pLinkSocket;
- }
- }
-
- //
- // Locate the port in the service list
- //
- pService = pPort->pService;
- pPreviousPort = pService->pPortList;
- if ( pPreviousPort == pPort ) {
- //
- // Remove this port from the head of the service list
- //
- pService->pPortList = pPort->pLinkService;
- }
- else {
- //
- // Locate the port in the middle of the service list
- //
- while (( NULL != pPreviousPort )
- && ( pPreviousPort->pLinkService != pPort )) {
- pPreviousPort = pPreviousPort->pLinkService;
- }
- if ( NULL != pPreviousPort ) {
- //
- // Remove the port from the middle of the service list
- //
- pPreviousPort->pLinkService = pPort->pLinkService;
- }
- }
-
- //
- // Empty the urgent receive queue
- //
pTcp4 = &pPort->Context.Tcp4;
- while ( NULL != pSocket->pRxOobPacketListHead ) {
- pPacket = pSocket->pRxOobPacketListHead;
- pSocket->pRxOobPacketListHead = pPacket->pNext;
- pSocket->RxOobBytes -= pPacket->Op.Tcp4Rx.ValidBytes;
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- }
- pSocket->pRxOobPacketListTail = NULL;
- ASSERT ( 0 == pSocket->RxOobBytes );
-
- //
- // Empty the receive queue
- //
- while ( NULL != pSocket->pRxPacketListHead ) {
- pPacket = pSocket->pRxPacketListHead;
- pSocket->pRxPacketListHead = pPacket->pNext;
- pSocket->RxBytes -= pPacket->Op.Tcp4Rx.ValidBytes;
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- }
- pSocket->pRxPacketListTail = NULL;
- ASSERT ( 0 == pSocket->RxBytes );
-
- //
- // Empty the receive free queue
- //
- while ( NULL != pSocket->pRxFree ) {
- pPacket = pSocket->pRxFree;
- pSocket->pRxFree = pPacket->pNext;
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- }
//
// Done with the connect event
@@ -1778,121 +1415,6 @@ EslTcpPortClose4 (
}
//
- // Done with the receive event
- //
- if ( NULL != pTcp4->RxToken.CompletionToken.Event ) {
- Status = gBS->CloseEvent ( pTcp4->RxToken.CompletionToken.Event );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Closed receive event\r\n",
- pTcp4->RxToken.CompletionToken.Event ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close the receive event, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the normal transmit event
- //
- if ( NULL != pTcp4->TxToken.CompletionToken.Event ) {
- Status = gBS->CloseEvent ( pTcp4->TxToken.CompletionToken.Event );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Closed normal transmit event\r\n",
- pTcp4->TxToken.CompletionToken.Event ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close the normal transmit event, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the urgent transmit event
- //
- if ( NULL != pTcp4->TxOobToken.CompletionToken.Event ) {
- Status = gBS->CloseEvent ( pTcp4->TxOobToken.CompletionToken.Event );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Closed urgent transmit event\r\n",
- pTcp4->TxOobToken.CompletionToken.Event ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close the urgent transmit event, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the TCP protocol
- //
- pTcp4Service = pService->pInterface;
- if ( NULL != pTcp4->pProtocol ) {
- Status = gBS->CloseProtocol ( pTcp4->Handle,
- &gEfiTcp4ProtocolGuid,
- pLayer->ImageHandle,
- NULL );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags,
- "0x%08x: gEfiTcp4ProtocolGuid closed on controller 0x%08x\r\n",
- pTcp4->pProtocol,
- pTcp4->Handle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close gEfiTcp4ProtocolGuid opened on controller 0x%08x, Status: %r\r\n",
- pTcp4->Handle,
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the TCP port
- //
- if ( NULL != pTcp4->Handle ) {
- Status = pTcp4Service->DestroyChild ( pTcp4Service,
- pTcp4->Handle );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Tcp4 port handle destroyed\r\n",
- pTcp4->Handle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
- "ERROR - Failed to destroy the Tcp4 port handle, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Release the port structure
- //
- Status = gBS->FreePool ( pPort );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Free pPort, %d bytes\r\n",
- pPort,
- sizeof ( *pPort )));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
- "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
- pPort,
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
-
- //
// Return the operation status
//
DBG_EXIT_STATUS ( Status );
@@ -1901,94 +1423,52 @@ EslTcpPortClose4 (
/**
- Process the port close completion
-
- @param Event The close completion event
-
- @param pPort The DT_PORT structure address
-
-**/
-VOID
-EslTcpPortCloseComplete4 (
- IN EFI_EVENT Event,
- IN DT_PORT * pPort
- )
-{
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_DONE;
-
- //
- // Release the resources once the receive operation completes
- //
- Status = EslTcpPortCloseRxDone4 ( pPort );
- DBG_EXIT_STATUS ( Status );
-}
+ Perform the network specific close operation on the port.
+ This routine performs a cancel operations on the TCPv4 port to
+ shutdown the receive operations on the port.
-/**
- Start the close operation on a TCP4 port, state 1.
+ This routine is called by the ::EslSocketPortCloseTxDone
+ routine after the port completes all of the transmission.
- Closing a port goes through the following states:
- 1. Port close starting - Mark the port as closing and wait for transmission to complete
- 2. Port TX close done - Transmissions complete, close the port and abort the receives
- 3. Port RX close done - Receive operations complete, close the port
- 4. Port closed - Release the port resources
-
- @param [in] pPort Address of the port structure.
- @param [in] bCloseNow Set TRUE to abort active transfers
- @param [in] DebugFlags Flags for debug messages
+ @param [in] pPort Address of an ::ESL_PORT structure.
@retval EFI_SUCCESS The port is closed, not normally returned
- @retval EFI_NOT_READY The port has started the closing process
+ @retval EFI_NOT_READY The port is still closing
@retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
most likely the routine was called already.
**/
EFI_STATUS
-EslTcpPortCloseStart4 (
- IN DT_PORT * pPort,
- IN BOOLEAN bCloseNow,
- IN UINTN DebugFlags
+EslTcp4PortCloseOp (
+ IN ESL_PORT * pPort
)
{
- DT_SOCKET * pSocket;
+ ESL_TCP4_CONTEXT * pTcp4;
+ EFI_TCP4_PROTOCOL * pTcp4Protocol;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Mark the port as closing
+ // Close the configured port
//
- Status = EFI_ALREADY_STARTED;
- pSocket = pPort->pSocket;
- pSocket->errno = EALREADY;
- if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {
-
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_STARTED;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
+ Status = EFI_SUCCESS;
+ pTcp4 = &pPort->Context.Tcp4;
+ pTcp4Protocol = pPort->pProtocol.TCPv4;
+ pTcp4->CloseToken.AbortOnClose = pPort->bCloseNow;
+ Status = pTcp4Protocol->Close ( pTcp4Protocol,
+ &pTcp4->CloseToken );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port close started\r\n",
pPort ));
- pPort->bCloseNow = bCloseNow;
- pPort->DebugFlags = DebugFlags;
-
- //
- // Determine if transmits are complete
- //
- Status = EslTcpPortCloseTxDone4 ( pPort );
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
+ "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
+ pPort,
+ Status ));
}
//
@@ -2000,562 +1480,224 @@ EslTcpPortCloseStart4 (
/**
- Port close state 3
+ Receive data from a network connection.
- Continue the close operation after the receive is complete.
+ This routine attempts to return buffered data to the caller. The
+ data is removed from the urgent queue if the message flag MSG_OOB
+ is specified, otherwise data is removed from the normal queue.
+ See the \ref ReceiveEngine section.
- @param [in] pPort Address of the port structure.
+ This routine is called by ::EslSocketReceive to handle the network
+ specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
+ sockets.
- @retval EFI_SUCCESS The port is closed
- @retval EFI_NOT_READY The port is still closing
- @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
- most likely the routine was called already.
+ @param [in] pPort Address of an ::ESL_PORT structure.
-**/
-EFI_STATUS
-EslTcpPortCloseRxDone4 (
- IN DT_PORT * pPort
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
+
+ @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
+
+ @param [in] BufferLength Length of the the buffer
+
+ @param [in] pBuffer Address of a buffer to receive the data.
+
+ @param [in] pDataLength Number of received data bytes in the buffer.
+
+ @param [out] pAddress Network address to receive the remote system address
+
+ @param [out] pSkipBytes Address to receive the number of bytes skipped
+
+ @return Returns the address of the next free byte in the buffer.
+
+ **/
+UINT8 *
+EslTcp4Receive (
+ IN ESL_PORT * pPort,
+ IN ESL_PACKET * pPacket,
+ IN BOOLEAN * pbConsumePacket,
+ IN size_t BufferLength,
+ IN UINT8 * pBuffer,
+ OUT size_t * pDataLength,
+ OUT struct sockaddr * pAddress,
+ OUT size_t * pSkipBytes
)
{
- PORT_STATE PortState;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_STATUS Status;
+ size_t DataLength;
+ struct sockaddr_in * pRemoteAddress;
+ ESL_TCP4_CONTEXT * pTcp4;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Verify that the port is closing
+ // Return the remote system address if requested
//
- Status = EFI_ALREADY_STARTED;
- PortState = pPort->State;
- if (( PORT_STATE_CLOSE_TX_DONE == PortState )
- || ( PORT_STATE_CLOSE_DONE == PortState )) {
+ if ( NULL != pAddress ) {
//
- // Determine if the receive operation is pending
+ // Build the remote address
//
- Status = EFI_NOT_READY;
pTcp4 = &pPort->Context.Tcp4;
- if ( NULL == pTcp4->pReceivePending ) {
- //
- // The receive operation is complete
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_RX_DONE;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
- pPort ));
-
- //
- // Determine if the close operation has completed
- //
- if ( PORT_STATE_CLOSE_DONE == PortState ) {
- //
- // The close operation has completed
- // Release the port resources
- //
- Status = EslTcpPortClose4 ( pPort );
- }
- else
- {
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close: Close operation still pending!\r\n",
- pPort ));
- }
- }
- else {
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close: Receive still pending!\r\n",
- pPort ));
- }
+ DEBUG (( DEBUG_RX,
+ "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
+ pTcp4->ConfigData.AccessPoint.RemotePort ));
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_addr ));
+ pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
}
//
- // Return the operation status
+ // Determine the amount of received data
//
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Port close state 2
-
- Continue the close operation after the transmission is complete.
-
- @param [in] pPort Address of the port structure.
-
- @retval EFI_SUCCESS The port is closed, not normally returned
- @retval EFI_NOT_READY The port is still closing
- @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
- most likely the routine was called already.
-
-**/
-EFI_STATUS
-EslTcpPortCloseTxDone4 (
- IN DT_PORT * pPort
- )
-{
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_TCP4_PROTOCOL * pTcp4Protocol;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
+ DataLength = pPacket->ValidBytes;
+ if ( BufferLength < DataLength ) {
+ DataLength = BufferLength;
+ }
//
- // Verify the socket layer synchronization
+ // Move the data into the buffer
//
- VERIFY_TPL ( TPL_SOCKETS );
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
+ pPort,
+ pPacket,
+ pBuffer,
+ DataLength ));
+ CopyMem ( pBuffer, pPacket->pBuffer, DataLength );
//
- // All transmissions are complete or must be stopped
- // Mark the port as TX complete
+ // Determine if the data is being read
//
- Status = EFI_ALREADY_STARTED;
- if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {
+ if ( *pbConsumePacket ) {
//
- // Verify that the transmissions are complete
+ // Account for the bytes consumed
//
- pSocket = pPort->pSocket;
- if ( pPort->bCloseNow
- || ( EFI_SUCCESS != pSocket->TxError )
- || (( 0 == pSocket->TxOobBytes )
- && ( 0 == pSocket->TxBytes ))) {
- //
- // Start the close operation on the port
- //
- pTcp4 = &pPort->Context.Tcp4;
- pTcp4->CloseToken.AbortOnClose = FALSE;
- pTcp4Protocol = pTcp4->pProtocol;
- if ( !pTcp4->bConfigured ) {
- //
- // Skip the close operation since the port is not
- // configured
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_DONE;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
- pPort ));
- Status = EFI_SUCCESS;
- }
- else {
- //
- // Close the configured port
- //
- Status = pTcp4Protocol->Close ( pTcp4Protocol,
- &pTcp4->CloseToken );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port close started\r\n",
- pPort ));
-
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_TX_DONE;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
- pPort ));
- }
- else {
- DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
- "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
- pPort,
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
+ pPacket->pBuffer += DataLength;
+ pPacket->ValidBytes -= DataLength;
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port account for 0x%08x bytes\r\n",
+ pPort,
+ DataLength ));
+ //
+ // Determine if the entire packet was consumed
+ //
+ if (( 0 == pPacket->ValidBytes )
+ || ( SOCK_STREAM != pPort->pSocket->Type )) {
//
- // Determine if the receive operation is pending
+ // All done with this packet
+ // Account for any discarded data
//
- if ( !EFI_ERROR ( Status )) {
- Status = EslTcpPortCloseRxDone4 ( pPort );
- }
+ *pSkipBytes = pPacket->ValidBytes;
}
- else {
+ else
+ {
//
- // Transmissions are still active, exit
+ // More data to consume later
//
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close: Transmits are still pending!\r\n",
- pPort ));
- Status = EFI_NOT_READY;
- pSocket->errno = EAGAIN;
+ *pbConsumePacket = FALSE;
}
}
//
- // Return the operation status
+ // Return the data length and the buffer address
//
- DBG_EXIT_STATUS ( Status );
- return Status;
+ *pDataLength = DataLength;
+ DBG_EXIT_HEX ( pBuffer );
+ return pBuffer;
}
/**
- Receive data from a network connection.
-
+ Get the remote socket address.
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @param [in] Flags Message control flags
-
- @param [in] BufferLength Length of the the buffer
-
- @param [in] pBuffer Address of a buffer to receive the data.
-
- @param [in] pDataLength Number of received data bytes in the buffer.
+ This routine returns the address of the remote connection point
+ associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
- @param [out] pAddress Network address to receive the remote system address
+ This routine is called by ::EslSocketGetPeerAddress to detemine
+ the TCPv4 address and por number associated with the network adapter.
- @param [in,out] pAddressLength Length of the remote network address structure
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @retval EFI_SUCCESS - Socket data successfully received
+ @param [out] pAddress Network address to receive the remote system address
- **/
-EFI_STATUS
-EslTcpReceive4 (
- IN DT_SOCKET * pSocket,
- IN INT32 Flags,
- IN size_t BufferLength,
- IN UINT8 * pBuffer,
- OUT size_t * pDataLength,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+**/
+VOID
+EslTcp4RemoteAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
)
{
- socklen_t AddressLength;
- size_t BytesToCopy;
- in_addr_t IpAddress;
- size_t LengthInBytes;
- DT_PACKET * pPacket;
- DT_PORT * pPort;
- DT_PACKET ** ppQueueHead;
- DT_PACKET ** ppQueueTail;
struct sockaddr_in * pRemoteAddress;
- size_t * pRxDataBytes;
- DT_TCP4_CONTEXT * pTcp4;
- struct sockaddr_in RemoteAddress;
- EFI_STATUS Status;
+ ESL_TCP4_CONTEXT * pTcp4;
DBG_ENTER ( );
//
- // Assume failure
- //
- Status = EFI_UNSUPPORTED;
- pSocket->errno = ENOTCONN;
-
- //
- // Verify that the socket is connected
+ // Return the remote address
//
- if (( SOCKET_STATE_CONNECTED == pSocket->State )
- || ( PORT_STATE_RX_ERROR == pSocket->State )) {
- //
- // Locate the port
- //
- pPort = pSocket->pPortList;
- if ( NULL != pPort ) {
- //
- // Determine the queue head
- //
- pTcp4 = &pPort->Context.Tcp4;
- if ( 0 != ( Flags & MSG_OOB )) {
- ppQueueHead = &pSocket->pRxOobPacketListHead;
- ppQueueTail = &pSocket->pRxOobPacketListTail;
- pRxDataBytes = &pSocket->RxOobBytes;
- }
- else {
- ppQueueHead = &pSocket->pRxPacketListHead;
- ppQueueTail = &pSocket->pRxPacketListTail;
- pRxDataBytes = &pSocket->RxBytes;
- }
-
- //
- // Determine if there is any data on the queue
- //
- pPacket = *ppQueueHead;
- if ( NULL != pPacket ) {
- //
- // Validate the return address parameters
- //
- if (( NULL == pAddress ) || ( NULL != pAddressLength )) {
- //
- // Return the remote system address if requested
- //
- if ( NULL != pAddress ) {
- //
- // Build the remote address
- //
- ZeroMem ( &RemoteAddress, sizeof ( RemoteAddress ));
- RemoteAddress.sin_len = sizeof ( RemoteAddress );
- RemoteAddress.sin_family = AF_INET;
- IpAddress = pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3];
- IpAddress <<= 8;
- IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2];
- IpAddress <<= 8;
- IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1];
- IpAddress <<= 8;
- IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0];
- RemoteAddress.sin_addr.s_addr = IpAddress;
- RemoteAddress.sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
-
- //
- // Copy the address
- //
- pRemoteAddress = (struct sockaddr_in *)pAddress;
- AddressLength = sizeof ( *pRemoteAddress );
- if ( AddressLength > *pAddressLength ) {
- AddressLength = *pAddressLength;
- }
- CopyMem ( pRemoteAddress,
- &RemoteAddress,
- AddressLength );
-
- //
- // Update the address length
- //
- *pAddressLength = AddressLength;
- }
-
- //
- // Copy the received data
- //
- LengthInBytes = 0;
- do {
- //
- // Determine the amount of received data
- //
- BytesToCopy = pPacket->Op.Tcp4Rx.ValidBytes;
- if (( BufferLength - LengthInBytes ) < BytesToCopy ) {
- BytesToCopy = BufferLength - LengthInBytes;
- }
- LengthInBytes += BytesToCopy;
-
- //
- // Move the data into the buffer
- //
- DEBUG (( DEBUG_RX,
- "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
- pPort,
- pPacket,
- pBuffer,
- BytesToCopy ));
- CopyMem ( pBuffer, pPacket->Op.Tcp4Rx.pBuffer, BytesToCopy );
-
- //
- // Determine if the data is being read
- //
- if ( 0 == ( Flags & MSG_PEEK )) {
- //
- // Account for the bytes consumed
- //
- pPacket->Op.Tcp4Rx.pBuffer += BytesToCopy;
- pPacket->Op.Tcp4Rx.ValidBytes -= BytesToCopy;
- *pRxDataBytes -= BytesToCopy;
- DEBUG (( DEBUG_RX,
- "0x%08x: Port account for 0x%08x bytes\r\n",
- pPort,
- BytesToCopy ));
-
- //
- // Determine if the entire packet was consumed
- //
- if (( 0 == pPacket->Op.Tcp4Rx.ValidBytes )
- || ( SOCK_STREAM != pSocket->Type )) {
- //
- // All done with this packet
- // Account for any discarded data
- //
- *pRxDataBytes -= pPacket->Op.Tcp4Rx.ValidBytes;
- if ( 0 != pPacket->Op.Tcp4Rx.ValidBytes ) {
- DEBUG (( DEBUG_RX,
- "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
- pPort,
- pPacket->Op.Tcp4Rx.ValidBytes ));
- }
-
- //
- // Remove this packet from the queue
- //
- *ppQueueHead = pPacket->pNext;
- if ( NULL == *ppQueueHead ) {
- *ppQueueTail = NULL;
- }
-
- //
- // Move the packet to the free queue
- //
- pPacket->pNext = pSocket->pRxFree;
- pSocket->pRxFree = pPacket;
- DEBUG (( DEBUG_RX,
- "0x%08x: Port freeing packet 0x%08x\r\n",
- pPort,
- pPacket ));
-
- //
- // Restart this receive operation if necessary
- //
- if (( NULL == pTcp4->pReceivePending )
- && ( MAX_RX_DATA > pSocket->RxBytes )) {
- EslTcpRxStart4 ( pPort );
- }
- }
- }
-
- //
- // Get the next packet
- //
- pPacket = *ppQueueHead;
- } while (( SOCK_STREAM == pSocket->Type )
- && ( NULL != pPacket )
- && ( 0 == ( Flags & MSG_PEEK ))
- && ( BufferLength > LengthInBytes ));
+ pTcp4 = &pPort->Context.Tcp4;
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ pRemoteAddress->sin_family = AF_INET;
+ pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_addr ));
- //
- // Return the data length
- //
- *pDataLength = LengthInBytes;
+ DBG_EXIT ( );
+}
- //
- // Successful operation
- //
- Status = EFI_SUCCESS;
- pSocket->errno = 0;
- }
- else {
- //
- // Bad return address pointer and length
- //
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
- }
- }
- else {
- //
- // The queue is empty
- // Determine if it is time to return the receive error
- //
- if ( EFI_ERROR ( pSocket->RxError )
- && ( NULL == pSocket->pRxPacketListHead )
- && ( NULL == pSocket->pRxOobPacketListHead )) {
- Status = pSocket->RxError;
- pSocket->RxError = EFI_SUCCESS;
- switch ( Status ) {
- default:
- pSocket->errno = EIO;
- break;
-
- case EFI_CONNECTION_FIN:
- //
- // Continue to return zero bytes received when the
- // peer has successfully closed the connection
- //
- pSocket->RxError = EFI_CONNECTION_FIN;
- *pDataLength = 0;
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
- break;
- case EFI_CONNECTION_REFUSED:
- pSocket->errno = ECONNREFUSED;
- break;
+/**
+ Set the remote address
- case EFI_CONNECTION_RESET:
- pSocket->errno = ECONNRESET;
- break;
+ This routine sets the remote address in the port.
- case EFI_HOST_UNREACHABLE:
- pSocket->errno = EHOSTUNREACH;
- break;
-
- case EFI_NETWORK_UNREACHABLE:
- pSocket->errno = ENETUNREACH;
- break;
-
- case EFI_PORT_UNREACHABLE:
- pSocket->errno = EPROTONOSUPPORT;
- break;
-
- case EFI_PROTOCOL_UNREACHABLE:
- pSocket->errno = ENOPROTOOPT;
- break;
- }
- }
- else {
- Status = EFI_NOT_READY;
- pSocket->errno = EAGAIN;
- }
- }
- }
- }
+ This routine is called by ::EslSocketConnect to specify the
+ remote network address.
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
+ @param [in] pPort Address of an ::ESL_PORT structure.
+ @param [in] pSockAddr Network address of the remote system.
-/**
- Cancel the receive operations
+ @param [in] SockAddrLength Length in bytes of the network address.
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @retval EFI_SUCCESS - The cancel was successful
+ @retval EFI_SUCCESS The operation was successful
**/
EFI_STATUS
-EslTcpRxCancel4 (
- IN DT_SOCKET * pSocket
+EslTcp4RemoteAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN socklen_t SockAddrLength
)
{
- DT_PACKET * pPacket;
- DT_PORT * pPort;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_TCP4_PROTOCOL * pTcp4Protocol;
+ CONST struct sockaddr_in * pRemoteAddress;
+ ESL_TCP4_CONTEXT * pTcp4;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Assume failure
- //
- Status = EFI_NOT_FOUND;
-
+ // Set the remote address
//
- // Locate the port
- //
- pPort = pSocket->pPortList;
- if ( NULL != pPort ) {
- //
- // Determine if a receive is pending
- //
- pTcp4 = &pPort->Context.Tcp4;
- pPacket = pTcp4->pReceivePending;
- if ( NULL != pPacket ) {
- //
- // Attempt to cancel the receive operation
- //
- pTcp4Protocol = pTcp4->pProtocol;
- Status = pTcp4Protocol->Cancel ( pTcp4Protocol,
- &pTcp4->RxToken.CompletionToken );
- if ( EFI_NOT_FOUND == Status ) {
- //
- // The receive is complete
- //
- Status = EFI_SUCCESS;
- }
- }
+ pTcp4 = &pPort->Context.Tcp4;
+ pRemoteAddress = (struct sockaddr_in *)pSockAddr;
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
+ pTcp4->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );
+ Status = EFI_SUCCESS;
+ if ( INADDR_BROADCAST == pRemoteAddress->sin_addr.s_addr ) {
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Invalid remote address\r\n" ));
+ Status = EFI_INVALID_PARAMETER;
+ pPort->pSocket->errno = EAFNOSUPPORT;
}
//
@@ -2569,321 +1711,107 @@ EslTcpRxCancel4 (
/**
Process the receive completion
+ This routine queues the data in FIFO order in either the urgent
+ or normal data queues depending upon the type of data received.
+ See the \ref ReceiveEngine section.
+
+ This routine is called by the TCPv4 driver when some data is
+ received.
+
Buffer the data that was just received.
- @param Event The receive completion event
+ @param [in] Event The receive completion event
- @param pPort The DT_PORT structure address
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
**/
VOID
-EslTcpRxComplete4 (
+EslTcp4RxComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_IO_MGMT * pIo
)
{
BOOLEAN bUrgent;
size_t LengthInBytes;
- DT_PACKET * pPacket;
- DT_PACKET * pPrevious;
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_PACKET * pPacket;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Mark this receive complete
+ // Get the operation status.
//
- pTcp4 = &pPort->Context.Tcp4;
- pPacket = pTcp4->pReceivePending;
- pTcp4->pReceivePending = NULL;
+ Status = pIo->Token.Tcp4Rx.CompletionToken.Status;
//
- // Determine if this receive was successful
+ // +--------------------+ +---------------------------+
+ // | ESL_IO_MGMT | | ESL_PACKET |
+ // | | | |
+ // | +---------------+ +-----------------------+ |
+ // | | Token | | EFI_TCP4_RECEIVE_DATA | |
+ // | | RxData --> | | |
+ // | | | +-----------------------+---+
+ // | | Event | | Data Buffer |
+ // +----+---------------+ | |
+ // | |
+ // +---------------------------+
//
- pSocket = pPort->pSocket;
- Status = pTcp4->RxToken.CompletionToken.Status;
- if (( !EFI_ERROR ( Status )) && ( !pSocket->bRxDisable )) {
- //
- // Set the buffer size and address
- //
- pPacket->Op.Tcp4Rx.pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;
- LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;
- pPacket->Op.Tcp4Rx.ValidBytes = LengthInBytes;
- pPacket->pNext = NULL;
-
- //
- // Queue this packet
- //
- bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;
- if ( bUrgent ) {
- //
- // Add packet to the urgent list
- //
- pPrevious = pSocket->pRxOobPacketListTail;
- if ( NULL == pPrevious ) {
- pSocket->pRxOobPacketListHead = pPacket;
- }
- else {
- pPrevious->pNext = pPacket;
- }
- pSocket->pRxOobPacketListTail = pPacket;
-
- //
- // Account for the urgent data
- //
- pSocket->RxOobBytes += LengthInBytes;
- }
- else {
- //
- // Add packet to the normal list
- //
- pPrevious = pSocket->pRxPacketListTail;
- if ( NULL == pPrevious ) {
- pSocket->pRxPacketListHead = pPacket;
- }
- else {
- pPrevious->pNext = pPacket;
- }
- pSocket->pRxPacketListTail = pPacket;
-
- //
- // Account for the normal data
- //
- pSocket->RxBytes += LengthInBytes;
- }
-
- //
- // Log the received data
- //
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "0x%08x: Packet queued on port 0x%08x with 0x%08x bytes of %s data\r\n",
- pPacket,
- pPort,
- LengthInBytes,
- bUrgent ? L"urgent" : L"normal" ));
-
- //
- // Attempt to restart this receive operation
- //
- if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
- EslTcpRxStart4 ( pPort );
- }
- else {
- DEBUG (( DEBUG_RX,
- "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
- pPort,
- pSocket->RxBytes ));
- }
- }
- else
- {
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "ERROR - Receiving packet 0x%08x, on port 0x%08x, Status:%r\r\n",
- pPacket,
- pPort,
- Status ));
-
- //
- // Receive error, free the packet save the error
- //
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- if ( !EFI_ERROR ( pSocket->RxError )) {
- pSocket->RxError = Status;
- }
-
- //
- // Update the port state
- //
- if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
- EslTcpPortCloseRxDone4 ( pPort );
- }
- else {
- if ( EFI_ERROR ( Status )) {
- pPort->State = PORT_STATE_RX_ERROR;
- }
- }
- }
-
- DBG_EXIT ( );
-}
-
-
-/**
- Start a receive operation
-
- @param [in] pPort Address of the DT_PORT structure.
-
- **/
-VOID
-EslTcpRxStart4 (
- IN DT_PORT * pPort
- )
-{
- size_t LengthInBytes;
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_TCP4_PROTOCOL * pTcp4Protocol;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
//
- // Determine if a receive is already pending
+ // Duplicate the buffer address and length for use by the
+ // buffer handling code in EslTcp4Receive. These fields are
+ // used when a partial read is done of the data from the
+ // packet.
//
- Status = EFI_SUCCESS;
- pPacket = NULL;
- pSocket = pPort->pSocket;
- pTcp4 = &pPort->Context.Tcp4;
- if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
- if (( NULL == pTcp4->pReceivePending )
- && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
- //
- // Determine if there are any free packets
- //
- pPacket = pSocket->pRxFree;
- LengthInBytes = sizeof ( pPacket->Op.Tcp4Rx.Buffer );
- if ( NULL != pPacket ) {
- //
- // Remove this packet from the free list
- //
- pSocket->pRxFree = pPacket->pNext;
- DEBUG (( DEBUG_RX,
- "0x%08x: Port removed packet 0x%08x from free list\r\n",
- pPort,
- pPacket ));
- }
- else {
- //
- // Allocate a packet structure
- //
- Status = EslSocketPacketAllocate ( &pPacket,
- sizeof ( pPacket->Op.Tcp4Rx ),
- DEBUG_RX );
- if ( EFI_ERROR ( Status )) {
- pPacket = NULL;
- DEBUG (( DEBUG_ERROR | DEBUG_RX,
- "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
- pPort,
- Status ));
- }
- }
-
- //
- // Determine if a packet is available
- //
- if ( NULL != pPacket ) {
- //
- // Initialize the buffer for receive
- //
- pTcp4->RxToken.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;
- pPacket->Op.Tcp4Rx.RxData.DataLength = (UINT32) LengthInBytes;
- pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;
- pPacket->Op.Tcp4Rx.RxData.FragmentTable [0].FragmentLength = (UINT32) LengthInBytes;
- pPacket->Op.Tcp4Rx.RxData.FragmentTable [0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer [0];
- pTcp4->pReceivePending = pPacket;
+ pPacket = pIo->pPacket;
+ pPacket->pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;
+ LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;
+ pPacket->ValidBytes = LengthInBytes;
- //
- // Start the receive on the packet
- //
- pTcp4Protocol = pTcp4->pProtocol;
- Status = pTcp4Protocol->Receive ( pTcp4Protocol,
- &pTcp4->RxToken );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "0x%08x: Packet receive pending on port 0x%08x\r\n",
- pPacket,
- pPort ));
- }
- else {
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
- pPort,
- Status ));
- pTcp4->pReceivePending = NULL;
- if ( !EFI_ERROR ( pSocket->RxError )) {
- //
- // Save the error status
- //
- pSocket->RxError = Status;
- }
- }
- }
- }
- }
+ //
+ // Get the data type so that it may be linked to the
+ // correct receive buffer list on the ESL_SOCKET structure
+ //
+ bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;
+ //
+ // Complete this request
+ //
+ EslSocketRxComplete ( pIo, Status, LengthInBytes, bUrgent );
DBG_EXIT ( );
}
/**
- Shutdown the TCP4 service.
+ Start a receive operation
- This routine undoes the work performed by ::TcpInitialize4.
+ This routine posts a receive buffer to the TCPv4 driver.
+ See the \ref ReceiveEngine section.
- @param [in] pService DT_SERVICE structure address
+ This support routine is called by EslSocketRxStart.
-**/
+ @param [in] pPort Address of an ::ESL_PORT structure.
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure.
+
+ **/
VOID
-EFIAPI
-EslTcpShutdown4 (
- IN DT_SERVICE * pService
+EslTcp4RxStart (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT * pIo
)
{
- DT_LAYER * pLayer;
- DT_PORT * pPort;
- DT_SERVICE * pPreviousService;
+ ESL_PACKET * pPacket;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Walk the list of ports
- //
- do {
- pPort = pService->pPortList;
- if ( NULL != pPort ) {
- //
- // Remove the port from the port list
- //
- pService->pPortList = pPort->pLinkService;
-
- //
- // Close the port
- // TODO: Fix this
- //
-// pPort->pfnClosePort ( pPort, DEBUG_LISTEN | DEBUG_CONNECTION );
- }
- } while ( NULL != pPort );
-
- //
- // Remove the service from the service list
+ // Initialize the buffer for receive
//
- pLayer = &mEslLayer;
- pPreviousService = pLayer->pTcp4List;
- if ( pService == pPreviousService ) {
- //
- // Remove the service from the beginning of the list
- //
- pLayer->pTcp4List = pService->pNext;
- }
- else {
- //
- // Remove the service from the middle of the list
- //
- while ( NULL != pPreviousService ) {
- if ( pService == pPreviousService->pNext ) {
- pPreviousService->pNext = pService->pNext;
- break;
- }
- }
- }
+ pPacket = pIo->pPacket;
+ pIo->Token.Tcp4Rx.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;
+ pPacket->Op.Tcp4Rx.RxData.DataLength = sizeof ( pPacket->Op.Tcp4Rx.Buffer );
+ pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;
+ pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentLength = pPacket->Op.Tcp4Rx.RxData.DataLength;
+ pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer[0];
DBG_EXIT ( );
}
@@ -2892,16 +1820,21 @@ EslTcpShutdown4 (
/**
Determine if the socket is configured.
+ This routine uses the flag ESL_SOCKET::bConfigured to determine
+ if the network layer's configuration routine has been called.
+
+ This routine is called by EslSocketIsConfigured to verify
+ that the socket has been configured.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
- @param [in] pSocket Address of a DT_SOCKET structure
-
@retval EFI_SUCCESS - The port is connected
@retval EFI_NOT_STARTED - The port is not connected
**/
EFI_STATUS
- EslTcpSocketIsConfigured4 (
- IN DT_SOCKET * pSocket
+ EslTcp4SocketIsConfigured (
+ IN ESL_SOCKET * pSocket
)
{
EFI_STATUS Status;
@@ -2924,22 +1857,22 @@ EslTcpShutdown4 (
/**
Buffer data for transmission over a network connection.
- This routine is called by the socket layer API to buffer
- data for transmission. When necessary, this routine will
- start the transmit engine that performs the data transmission
- on the network connection.
+ This routine buffers data for the transmit engine in one of two
+ queues, one for urgent (out-of-band) data and the other for normal
+ data. The urgent data is provided to TCP as soon as it is available,
+ allowing the TCP layer to schedule transmission of the urgent data
+ between packets of normal data.
- The transmit engine uses two queues, one for urgent (out-of-band)
- data and the other for normal data. The urgent data is provided
- to TCP as soon as it is available, allowing the TCP layer to
- schedule transmission of the urgent data between packets of normal
- data.
+ This routine is called by ::EslSocketTransmit to buffer
+ data for transmission. When the \ref TransmitEngine has resources,
+ this routine will start the transmission of the next buffer on
+ the network connection.
Transmission errors are returned during the next transmission or
during the close operation. Only buffering errors are returned
during the current transmission attempt.
- @param [in] pSocket Address of a DT_SOCKET structure
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
@param [in] Flags Message control flags
@@ -2949,27 +1882,34 @@ EslTcpShutdown4 (
@param [in] pDataLength Number of received data bytes in the buffer.
+ @param [in] pAddress Network address of the remote system address
+
+ @param [in] AddressLength Length of the remote network address structure
+
@retval EFI_SUCCESS - Socket data successfully buffered
**/
EFI_STATUS
-EslTcpTxBuffer4 (
- IN DT_SOCKET * pSocket,
+EslTcp4TxBuffer (
+ IN ESL_SOCKET * pSocket,
IN int Flags,
IN size_t BufferLength,
IN CONST UINT8 * pBuffer,
- OUT size_t * pDataLength
+ OUT size_t * pDataLength,
+ IN const struct sockaddr * pAddress,
+ IN socklen_t AddressLength
)
{
BOOLEAN bUrgent;
- DT_PACKET * pPacket;
- DT_PACKET * pPreviousPacket;
- DT_PACKET ** ppPacket;
- DT_PACKET ** ppQueueHead;
- DT_PACKET ** ppQueueTail;
- DT_PORT * pPort;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_TCP4_IO_TOKEN * pToken;
+ BOOLEAN bUrgentQueue;
+ ESL_PACKET * pPacket;
+ ESL_IO_MGMT ** ppActive;
+ ESL_IO_MGMT ** ppFree;
+ ESL_PORT * pPort;
+ ESL_PACKET ** ppQueueHead;
+ ESL_PACKET ** ppQueueTail;
+ ESL_PACKET * pPreviousPacket;
+ ESL_TCP4_CONTEXT * pTcp4;
size_t * pTxBytes;
EFI_TCP4_TRANSMIT_DATA * pTxData;
EFI_STATUS Status;
@@ -2982,7 +1922,7 @@ EslTcpTxBuffer4 (
//
Status = EFI_UNSUPPORTED;
pSocket->errno = ENOTCONN;
- * pDataLength = 0;
+ *pDataLength = 0;
//
// Verify that the socket is connected
@@ -2998,18 +1938,21 @@ EslTcpTxBuffer4 (
//
pTcp4 = &pPort->Context.Tcp4;
bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
- if ( bUrgent ) {
+ bUrgentQueue = bUrgent
+ && ( !pSocket->bOobInLine )
+ && pSocket->pApi->bOobSupported;
+ if ( bUrgentQueue ) {
ppQueueHead = &pSocket->pTxOobPacketListHead;
ppQueueTail = &pSocket->pTxOobPacketListTail;
- ppPacket = &pTcp4->pTxOobPacket;
- pToken = &pTcp4->TxOobToken;
+ ppActive = &pPort->pTxOobActive;
+ ppFree = &pPort->pTxOobFree;
pTxBytes = &pSocket->TxOobBytes;
}
else {
ppQueueHead = &pSocket->pTxPacketListHead;
ppQueueTail = &pSocket->pTxPacketListTail;
- ppPacket = &pTcp4->pTxPacket;
- pToken = &pTcp4->TxToken;
+ ppActive = &pPort->pTxActive;
+ ppFree = &pPort->pTxFree;
pTxBytes = &pSocket->TxBytes;
}
@@ -3018,6 +1961,15 @@ EslTcpTxBuffer4 (
// transmit operation
//
if ( pSocket->MaxTxBuf > *pTxBytes ) {
+ if ( pPort->bTxFlowControl ) {
+ DEBUG (( DEBUG_TX,
+ "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",
+ pPort,
+ pSocket->MaxTxBuf,
+ *pTxBytes ));
+ pPort->bTxFlowControl = FALSE;
+ }
+
//
// Attempt to allocate the packet
//
@@ -3025,13 +1977,14 @@ EslTcpTxBuffer4 (
sizeof ( pPacket->Op.Tcp4Tx )
- sizeof ( pPacket->Op.Tcp4Tx.Buffer )
+ BufferLength,
+ 0,
DEBUG_TX );
if ( !EFI_ERROR ( Status )) {
//
// Initialize the transmit operation
//
pTxData = &pPacket->Op.Tcp4Tx.TxData;
- pTxData->Push = TRUE;
+ pTxData->Push = TRUE || bUrgent;
pTxData->Urgent = bUrgent;
pTxData->DataLength = (UINT32) BufferLength;
pTxData->FragmentCount = 1;
@@ -3078,7 +2031,7 @@ EslTcpTxBuffer4 (
DEBUG (( DEBUG_TX,
"0x%08x: Packet on %s transmit list\r\n",
pPacket,
- bUrgent ? L"urgent" : L"normal" ));
+ bUrgentQueue ? L"urgent" : L"normal" ));
//
// Account for the buffered data
@@ -3089,12 +2042,12 @@ EslTcpTxBuffer4 (
//
// Start the transmit engine if it is idle
//
- if ( NULL == *ppPacket ) {
- EslTcpTxStart4 ( pSocket->pPortList,
- pToken,
- ppQueueHead,
- ppQueueTail,
- ppPacket );
+ if ( NULL != *ppFree ) {
+ EslSocketTxStart ( pPort,
+ ppQueueHead,
+ ppQueueTail,
+ ppActive,
+ ppFree );
}
}
else {
@@ -3124,6 +2077,14 @@ EslTcpTxBuffer4 (
}
}
else {
+ if ( !pPort->bTxFlowControl ) {
+ DEBUG (( DEBUG_TX,
+ "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",
+ pPort,
+ pSocket->MaxTxBuf,
+ *pTxBytes ));
+ pPort->bTxFlowControl = TRUE;
+ }
//
// Not enough buffer space available
//
@@ -3144,104 +2105,56 @@ EslTcpTxBuffer4 (
/**
Process the normal data transmit completion
- @param Event The normal transmit completion event
+ This routine use ::EslSocketTxComplete to perform the transmit
+ completion processing for normal data.
- @param pPort The DT_PORT structure address
+ This routine is called by the TCPv4 network layer when a
+ normal data transmit request completes.
+
+ @param [in] Event The normal transmit completion event
+
+ @param [in] pIo The ESL_IO_MGMT structure address
**/
VOID
-EslTcpTxComplete4 (
+EslTcp4TxComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_IO_MGMT * pIo
)
{
UINT32 LengthInBytes;
- DT_PACKET * pCurrentPacket;
- DT_PACKET * pNextPacket;
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
DBG_ENTER ( );
-
+
//
// Locate the active transmit packet
//
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
pSocket = pPort->pSocket;
- pTcp4 = &pPort->Context.Tcp4;
- pPacket = pTcp4->pTxPacket;
-
+
//
- // Mark this packet as complete
+ // Get the transmit length and status
//
- pTcp4->pTxPacket = NULL;
LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;
pSocket->TxBytes -= LengthInBytes;
-
- //
- // Save any transmit error
- //
- Status = pTcp4->TxToken.CompletionToken.Status;
- if ( EFI_ERROR ( Status )) {
- if ( !EFI_ERROR ( pSocket->TxError )) {
- pSocket->TxError = Status;
- }
- DEBUG (( DEBUG_TX | DEBUG_INFO,
- "ERROR - Transmit failure for packet 0x%08x, Status: %r\r\n",
- pPacket,
- Status ));
+ Status = pIo->Token.Tcp4Tx.CompletionToken.Status;
- //
- // Empty the normal transmit list
- //
- pCurrentPacket = pPacket;
- pNextPacket = pSocket->pTxPacketListHead;
- while ( NULL != pNextPacket ) {
- pPacket = pNextPacket;
- pNextPacket = pPacket->pNext;
- EslSocketPacketFree ( pPacket, DEBUG_TX );
- }
- pSocket->pTxPacketListHead = NULL;
- pSocket->pTxPacketListTail = NULL;
- pPacket = pCurrentPacket;
- }
- else
- {
- DEBUG (( DEBUG_TX | DEBUG_INFO,
- "0x%08x: Packet transmitted %d bytes successfully\r\n",
- pPacket,
- LengthInBytes ));
-
- //
- // Verify the transmit engine is still running
- //
- if ( !pPort->bCloseNow ) {
- //
- // Start the next packet transmission
- //
- EslTcpTxStart4 ( pPort,
- &pTcp4->TxToken,
- &pSocket->pTxPacketListHead,
- &pSocket->pTxPacketListTail,
- &pTcp4->pTxPacket );
- }
- }
-
- //
- // Release this packet
//
- EslSocketPacketFree ( pPacket, DEBUG_TX );
-
- //
- // Finish the close operation if necessary
+ // Complete the transmit operation
//
- if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
- //
- // Indicate that the transmit is complete
- //
- EslTcpPortCloseTxDone4 ( pPort );
- }
+ EslSocketTxComplete ( pIo,
+ LengthInBytes,
+ Status,
+ "Normal ",
+ &pSocket->pTxPacketListHead,
+ &pSocket->pTxPacketListTail,
+ &pPort->pTxActive,
+ &pPort->pTxFree );
DBG_EXIT ( );
}
@@ -3249,23 +2162,27 @@ EslTcpTxComplete4 (
/**
Process the urgent data transmit completion
- @param Event The urgent transmit completion event
+ This routine use ::EslSocketTxComplete to perform the transmit
+ completion processing for urgent data.
- @param pPort The DT_PORT structure address
+ This routine is called by the TCPv4 network layer when a
+ urgent data transmit request completes.
+
+ @param [in] Event The urgent transmit completion event
+
+ @param [in] pIo The ESL_IO_MGMT structure address
**/
VOID
-EslTcpTxOobComplete4 (
+EslTcp4TxOobComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_IO_MGMT * pIo
)
{
UINT32 LengthInBytes;
- DT_PACKET * pCurrentPacket;
- DT_PACKET * pNextPacket;
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -3273,150 +2190,70 @@ EslTcpTxOobComplete4 (
//
// Locate the active transmit packet
//
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
pSocket = pPort->pSocket;
- pTcp4 = &pPort->Context.Tcp4;
- pPacket = pTcp4->pTxOobPacket;
//
- // Mark this packet as complete
+ // Get the transmit length and status
//
- pTcp4->pTxOobPacket = NULL;
LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;
pSocket->TxOobBytes -= LengthInBytes;
+ Status = pIo->Token.Tcp4Tx.CompletionToken.Status;
//
- // Save any transmit error
- //
- Status = pTcp4->TxOobToken.CompletionToken.Status;
- if ( EFI_ERROR ( Status )) {
- if ( !EFI_ERROR ( Status )) {
- pSocket->TxError = Status;
- }
- DEBUG (( DEBUG_TX | DEBUG_INFO,
- "ERROR - Transmit failure for urgent packet 0x%08x, Status: %r\r\n",
- pPacket,
- Status ));
-
-
- //
- // Empty the OOB transmit list
- //
- pCurrentPacket = pPacket;
- pNextPacket = pSocket->pTxOobPacketListHead;
- while ( NULL != pNextPacket ) {
- pPacket = pNextPacket;
- pNextPacket = pPacket->pNext;
- EslSocketPacketFree ( pPacket, DEBUG_TX );
- }
- pSocket->pTxOobPacketListHead = NULL;
- pSocket->pTxOobPacketListTail = NULL;
- pPacket = pCurrentPacket;
- }
- else
- {
- DEBUG (( DEBUG_TX | DEBUG_INFO,
- "0x%08x: Urgent packet transmitted %d bytes successfully\r\n",
- pPacket,
- LengthInBytes ));
-
- //
- // Verify the transmit engine is still running
- //
- if ( !pPort->bCloseNow ) {
- //
- // Start the next packet transmission
- //
- EslTcpTxStart4 ( pPort,
- &pTcp4->TxOobToken,
- &pSocket->pTxOobPacketListHead,
- &pSocket->pTxOobPacketListTail,
- &pTcp4->pTxOobPacket );
- }
- }
-
- //
- // Release this packet
- //
- EslSocketPacketFree ( pPacket, DEBUG_TX );
-
- //
- // Finish the close operation if necessary
+ // Complete the transmit operation
//
- if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
- //
- // Indicate that the transmit is complete
- //
- EslTcpPortCloseTxDone4 ( pPort );
- }
+ EslSocketTxComplete ( pIo,
+ LengthInBytes,
+ Status,
+ "Urgent ",
+ &pSocket->pTxOobPacketListHead,
+ &pSocket->pTxOobPacketListTail,
+ &pPort->pTxOobActive,
+ &pPort->pTxOobFree );
DBG_EXIT ( );
}
/**
- Transmit data using a network connection.
-
-
- @param [in] pPort Address of a DT_PORT structure
- @param [in] pToken Address of either the OOB or normal transmit token
- @param [in] ppQueueHead Transmit queue head address
- @param [in] ppQueueTail Transmit queue tail address
- @param [in] ppPacket Active transmit packet address
-
- **/
-VOID
-EslTcpTxStart4 (
- IN DT_PORT * pPort,
- IN EFI_TCP4_IO_TOKEN * pToken,
- IN DT_PACKET ** ppQueueHead,
- IN DT_PACKET ** ppQueueTail,
- IN DT_PACKET ** ppPacket
- )
-{
- DT_PACKET * pNextPacket;
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- EFI_TCP4_PROTOCOL * pTcp4Protocol;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Assume success
- //
- Status = EFI_SUCCESS;
-
- //
- // Get the packet from the queue head
- //
- pPacket = *ppQueueHead;
- if ( NULL != pPacket ) {
- //
- // Remove the packet from the queue
- //
- pNextPacket = pPacket->pNext;
- *ppQueueHead = pNextPacket;
- if ( NULL == pNextPacket ) {
- *ppQueueTail = NULL;
- }
-
- //
- // Set the packet as active
- //
- *ppPacket = pPacket;
-
- //
- // Start the transmit operation
- //
- pTcp4Protocol = pPort->Context.Tcp4.pProtocol;
- pToken->Packet.TxData = &pPacket->Op.Tcp4Tx.TxData;
- Status = pTcp4Protocol->Transmit ( pTcp4Protocol, pToken );
- if ( EFI_ERROR ( Status )) {
- pSocket = pPort->pSocket;
- if ( EFI_SUCCESS == pSocket->TxError ) {
- pSocket->TxError = Status;
- }
- }
- }
-
- DBG_EXIT ( );
-}
+ Interface between the socket layer and the network specific
+ code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
+ over TCPv4.
+**/
+CONST ESL_PROTOCOL_API cEslTcp4Api = {
+ "TCPv4",
+ IPPROTO_TCP,
+ OFFSET_OF ( ESL_PORT, Context.Tcp4.ConfigData ),
+ OFFSET_OF ( ESL_LAYER, pTcp4List ),
+ OFFSET_OF ( struct sockaddr_in, sin_zero ),
+ sizeof ( struct sockaddr_in ),
+ AF_INET,
+ sizeof (((ESL_PACKET *)0 )->Op.Tcp4Rx ),
+ OFFSET_OF ( ESL_PACKET, Op.Tcp4Rx.Buffer ) - OFFSET_OF ( ESL_PACKET, Op ),
+ OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Rx.Packet.RxData ),
+ TRUE,
+ EADDRINUSE,
+ EslTcp4Accept,
+ EslTcp4ConnectPoll,
+ EslTcp4ConnectStart,
+ EslTcp4SocketIsConfigured,
+ EslTcp4LocalAddressGet,
+ EslTcp4LocalAddressSet,
+ EslTcp4Listen,
+ NULL, // OptionGet
+ NULL, // OptionSet
+ EslTcp4PacketFree,
+ EslTcp4PortAllocate,
+ EslTcp4PortClose,
+ EslTcp4PortCloseOp,
+ FALSE,
+ EslTcp4Receive,
+ EslTcp4RemoteAddressGet,
+ EslTcp4RemoteAddressSet,
+ EslTcp4RxComplete,
+ EslTcp4RxStart,
+ EslTcp4TxBuffer,
+ EslTcp4TxComplete,
+ EslTcp4TxOobComplete
+};
diff --git a/StdLib/EfiSocketLib/Udp4.c b/StdLib/EfiSocketLib/Udp4.c
index 95fc66517a..e1500d3f9f 100644
--- a/StdLib/EfiSocketLib/Udp4.c
+++ b/StdLib/EfiSocketLib/Udp4.c
@@ -16,633 +16,153 @@
/**
- Bind a name to a socket.
-
- The ::UdpBind4 routine connects a name to a UDP4 stack on the local machine.
-
- The configure call to the UDP4 driver occurs on the first poll, recv, recvfrom,
- send or sentto call. Until then, all changes are made in the local UDP context
- structure.
-
- @param [in] pSocket Address of the socket structure.
-
- @param [in] pSockAddr Address of a sockaddr structure that contains the
- connection point on the local machine. An IPv4 address
- of INADDR_ANY specifies that the connection is made to
- all of the network stacks on the platform. Specifying a
- specific IPv4 address restricts the connection to the
- network stack supporting that address. Specifying zero
- for the port causes the network layer to assign a port
- number from the dynamic range. Specifying a specific
- port number causes the network layer to use that port.
-
- @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.
-
- @retval EFI_SUCCESS - Socket successfully created
-
- **/
-EFI_STATUS
-EslUdpBind4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
- )
-{
- EFI_HANDLE ChildHandle;
- DT_LAYER * pLayer;
- DT_PORT * pPort;
- DT_SERVICE * pService;
- CONST struct sockaddr_in * pIp4Address;
- EFI_SERVICE_BINDING_PROTOCOL * pUdp4Service;
- EFI_STATUS Status;
- EFI_STATUS TempStatus;
-
- DBG_ENTER ( );
-
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Assume success
- //
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
-
- //
- // Validate the address length
- //
- pIp4Address = (CONST struct sockaddr_in *) pSockAddr;
- if ( SockAddrLength >= ( sizeof ( *pIp4Address )
- - sizeof ( pIp4Address->sin_zero ))) {
-
- //
- // Walk the list of services
- //
- pLayer = &mEslLayer;
- pService = pLayer->pUdp4List;
- while ( NULL != pService ) {
-
- //
- // Create the UDP port
- //
- pUdp4Service = pService->pInterface;
- ChildHandle = NULL;
- Status = pUdp4Service->CreateChild ( pUdp4Service,
- &ChildHandle );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_BIND | DEBUG_POOL,
- "0x%08x: Udp4 port handle created\r\n",
- ChildHandle ));
-
- //
- // Open the port
- //
- Status = EslUdpPortAllocate4 ( pSocket,
- pService,
- ChildHandle,
- (UINT8 *) &pIp4Address->sin_addr.s_addr,
- SwapBytes16 ( pIp4Address->sin_port ),
- DEBUG_BIND,
- &pPort );
- }
- else {
- DEBUG (( DEBUG_BIND | DEBUG_POOL,
- "ERROR - Failed to open Udp4 port handle, Status: %r\r\n",
- Status ));
- ChildHandle = NULL;
- }
-
- //
- // Close the port if necessary
- //
- if (( EFI_ERROR ( Status )) && ( NULL != ChildHandle )) {
- TempStatus = pUdp4Service->DestroyChild ( pUdp4Service,
- ChildHandle );
- if ( !EFI_ERROR ( TempStatus )) {
- DEBUG (( DEBUG_BIND | DEBUG_POOL,
- "0x%08x: Udp4 port handle destroyed\r\n",
- ChildHandle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,
- "ERROR - Failed to destroy the Udp4 port handle 0x%08x, Status: %r\r\n",
- ChildHandle,
- TempStatus ));
- ASSERT ( EFI_SUCCESS == TempStatus );
- }
- }
-
- //
- // Set the next service
- //
- pService = pService->pNext;
- }
-
- //
- // Verify that at least one network connection was found
- //
- if ( NULL == pSocket->pPortList ) {
- DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
- "Socket address %d.%d.%d.%d (0x%08x) is not available!\r\n",
- ( pIp4Address->sin_addr.s_addr >> 24 ) & 0xff,
- ( pIp4Address->sin_addr.s_addr >> 16 ) & 0xff,
- ( pIp4Address->sin_addr.s_addr >> 8 ) & 0xff,
- pIp4Address->sin_addr.s_addr & 0xff,
- pIp4Address->sin_addr.s_addr ));
- pSocket->errno = EADDRNOTAVAIL;
- Status = EFI_INVALID_PARAMETER;
- }
- }
- else {
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid Udp4 address length: %d\r\n",
- SockAddrLength ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
- }
-
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
+ Get the local socket address
-/**
- Initialize the UDP4 service.
+ This routine returns the IPv4 address and UDP port number associated
+ with the local socket.
- This routine initializes the UDP4 service after its service binding
- protocol was located on a controller.
+ This routine is called by ::EslSocketGetLocalAddress to determine the
+ network address for the SOCK_DGRAM socket.
- @param [in] pService DT_SERVICE structure address
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @retval EFI_SUCCESS The service was properly initialized
- @retval other A failure occurred during the service initialization
+ @param [out] pSockAddr Network address to receive the local system address
**/
-EFI_STATUS
-EFIAPI
-EslUdpInitialize4 (
- IN DT_SERVICE * pService
+VOID
+EslUdp4LocalAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pSockAddr
)
{
- DT_LAYER * pLayer;
- EFI_STATUS Status;
+ struct sockaddr_in * pLocalAddress;
+ ESL_UDP4_CONTEXT * pUdp4;
DBG_ENTER ( );
//
- // Identify the service
- //
- pService->NetworkType = NETWORK_TYPE_UDP4;
-
- //
- // Connect this service to the service list
- //
- pLayer = &mEslLayer;
- pService->pNext = pLayer->pUdp4List;
- pLayer->pUdp4List = pService;
-
+ // Return the local address
//
- // Assume the list is empty
- //
- Status = EFI_SUCCESS;
+ pUdp4 = &pPort->Context.Udp4;
+ pLocalAddress = (struct sockaddr_in *)pSockAddr;
+ pLocalAddress->sin_family = AF_INET;
+ pLocalAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.StationPort );
+ CopyMem ( &pLocalAddress->sin_addr,
+ &pUdp4->ConfigData.StationAddress.Addr[0],
+ sizeof ( pLocalAddress->sin_addr ));
- //
- // Return the initialization status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
+ DBG_EXIT ( );
}
/**
- Allocate and initialize a DT_PORT structure.
+ Set the local port address.
- @param [in] pSocket Address of the socket structure.
- @param [in] pService Address of the DT_SERVICE structure.
- @param [in] ChildHandle Udp4 child handle
- @param [in] pIpAddress Buffer containing IP4 network address of the local host
- @param [in] PortNumber Udp4 port number
- @param [in] DebugFlags Flags for debug messages
- @param [out] ppPort Buffer to receive new DT_PORT structure address
+ This routine sets the local port address.
- @retval EFI_SUCCESS - Socket successfully created
+ This support routine is called by ::EslSocketPortAllocate.
+
+ @param [in] pPort Address of an ESL_PORT structure
+ @param [in] pSockAddr Address of a sockaddr structure that contains the
+ connection point on the local machine. An IPv4 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv4 address restricts the connection to the
+ network stack supporting that address. Specifying zero
+ for the port causes the network layer to assign a port
+ number from the dynamic range. Specifying a specific
+ port number causes the network layer to use that port.
+
+ @param [in] bBindTest TRUE = run bind testing
+
+ @retval EFI_SUCCESS The operation was successful
**/
EFI_STATUS
-EslUdpPortAllocate4 (
- IN DT_SOCKET * pSocket,
- IN DT_SERVICE * pService,
- IN EFI_HANDLE ChildHandle,
- IN CONST UINT8 * pIpAddress,
- IN UINT16 PortNumber,
- IN UINTN DebugFlags,
- OUT DT_PORT ** ppPort
+EslUdp4LocalAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest
)
{
- UINTN LengthInBytes;
EFI_UDP4_CONFIG_DATA * pConfig;
- DT_LAYER * pLayer;
- DT_PORT * pPort;
- DT_UDP4_CONTEXT * pUdp4;
+ CONST struct sockaddr_in * pIpAddress;
+ CONST UINT8 * pIpv4Address;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Use for/break instead of goto
- for ( ; ; ) {
- //
- // Allocate a port structure
- //
- pLayer = &mEslLayer;
- LengthInBytes = sizeof ( *pPort );
- Status = gBS->AllocatePool ( EfiRuntimeServicesData,
- LengthInBytes,
- (VOID **)&pPort );
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,
- "ERROR - Failed to allocate the port structure, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- pPort = NULL;
- break;
- }
- DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
- "0x%08x: Allocate pPort, %d bytes\r\n",
- pPort,
- LengthInBytes ));
-
- //
- // Initialize the port
- //
- ZeroMem ( pPort, LengthInBytes );
- pPort->Signature = PORT_SIGNATURE;
- pPort->pService = pService;
- pPort->pSocket = pSocket;
- pPort->pfnCloseStart = EslUdpPortCloseStart4;
- pPort->DebugFlags = DebugFlags;
-
+ // Validate the address
+ //
+ pIpAddress = (struct sockaddr_in *)pSockAddr;
+ if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {
//
- // Allocate the receive event
+ // The local address must not be the broadcast address
//
- pUdp4 = &pPort->Context.Udp4;
- Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
- TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslUdpRxComplete4,
- pPort,
- &pUdp4->RxToken.Event);
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to create the receive event, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- break;
- }
- DEBUG (( DEBUG_RX | DEBUG_POOL,
- "0x%08x: Created receive event\r\n",
- pUdp4->RxToken.Event ));
-
+ Status = EFI_INVALID_PARAMETER;
+ pPort->pSocket->errno = EADDRNOTAVAIL;
+ }
+ else {
//
- // Allocate the transmit event
+ // Set the local address
//
- Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
- TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslUdpTxComplete4,
- pPort,
- &pUdp4->TxToken.Event);
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to create the transmit event, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- break;
- }
- DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
- "0x%08x: Created transmit event\r\n",
- pUdp4->TxToken.Event ));
+ pIpAddress = (struct sockaddr_in *)pSockAddr;
+ pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;
+ pConfig = &pPort->Context.Udp4.ConfigData;
+ pConfig->StationAddress.Addr[0] = pIpv4Address[0];
+ pConfig->StationAddress.Addr[1] = pIpv4Address[1];
+ pConfig->StationAddress.Addr[2] = pIpv4Address[2];
+ pConfig->StationAddress.Addr[3] = pIpv4Address[3];
//
- // Open the port protocol
+ // Determine if the default address is used
//
- Status = gBS->OpenProtocol (
- ChildHandle,
- &gEfiUdp4ProtocolGuid,
- (VOID **) &pUdp4->pProtocol,
- pLayer->ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to open gEfiUdp4ProtocolGuid on controller 0x%08x\r\n",
- pUdp4->Handle ));
- pSocket->errno = EEXIST;
- break;
- }
- DEBUG (( DebugFlags,
- "0x%08x: gEfiUdp4ProtocolGuid opened on controller 0x%08x\r\n",
- pUdp4->pProtocol,
- ChildHandle ));
-
+ pConfig->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );
+
//
- // Set the port address
+ // Set the subnet mask
//
- pUdp4->Handle = ChildHandle;
- pConfig = &pPort->Context.Udp4.ConfigData;
- pConfig->StationPort = PortNumber;
- if (( 0 == pIpAddress[0])
- && ( 0 == pIpAddress[1])
- && ( 0 == pIpAddress[2])
- && ( 0 == pIpAddress[3])) {
- pConfig->UseDefaultAddress = TRUE;
+ if ( pConfig->UseDefaultAddress ) {
+ pConfig->SubnetMask.Addr[0] = 0;
+ pConfig->SubnetMask.Addr[1] = 0;
+ pConfig->SubnetMask.Addr[2] = 0;
+ pConfig->SubnetMask.Addr[3] = 0;
}
else {
- pConfig->StationAddress.Addr[0] = pIpAddress[0];
- pConfig->StationAddress.Addr[1] = pIpAddress[1];
- pConfig->StationAddress.Addr[2] = pIpAddress[2];
- pConfig->StationAddress.Addr[3] = pIpAddress[3];
pConfig->SubnetMask.Addr[0] = 0xff;
pConfig->SubnetMask.Addr[1] = 0xff;
pConfig->SubnetMask.Addr[2] = 0xff;
pConfig->SubnetMask.Addr[3] = 0xff;
}
- pConfig->TimeToLive = 255;
- pConfig->AcceptAnyPort = FALSE;
- pConfig->AcceptBroadcast = FALSE;
- pConfig->AcceptPromiscuous = FALSE;
- pConfig->AllowDuplicatePort = TRUE;
- pConfig->DoNotFragment = TRUE;
-
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Add this port to the socket
- //
- pPort->pLinkSocket = pSocket->pPortList;
- pSocket->pPortList = pPort;
- DEBUG (( DebugFlags,
- "0x%08x: Socket adding port: 0x%08x\r\n",
- pSocket,
- pPort ));
-
- //
- // Add this port to the service
- //
- pPort->pLinkService = pService->pPortList;
- pService->pPortList = pPort;
-
- //
- // Return the port
- //
- *ppPort = pPort;
- break;
- }
-
- //
- // Clean up after the error if necessary
- //
- if (( EFI_ERROR ( Status )) && ( NULL != pPort )) {
- //
- // Close the port
- //
- EslUdpPortClose4 ( pPort );
- }
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Close a UDP4 port.
-
- This routine releases the resources allocated by
- ::UdpPortAllocate4().
-
- @param [in] pPort Address of the port structure.
-
- @retval EFI_SUCCESS The port is closed
- @retval other Port close error
-
-**/
-EFI_STATUS
-EslUdpPortClose4 (
- IN DT_PORT * pPort
- )
-{
- UINTN DebugFlags;
- DT_LAYER * pLayer;
- DT_PACKET * pPacket;
- DT_PORT * pPreviousPort;
- DT_SERVICE * pService;
- DT_SOCKET * pSocket;
- EFI_SERVICE_BINDING_PROTOCOL * pUdp4Service;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Assume success
- //
- Status = EFI_SUCCESS;
- pSocket = pPort->pSocket;
- pSocket->errno = 0;
- //
- // Locate the port in the socket list
- //
- pLayer = &mEslLayer;
- DebugFlags = pPort->DebugFlags;
- pPreviousPort = pSocket->pPortList;
- if ( pPreviousPort == pPort ) {
- //
- // Remove this port from the head of the socket list
- //
- pSocket->pPortList = pPort->pLinkSocket;
- }
- else {
//
- // Locate the port in the middle of the socket list
+ // Validate the IP address
//
- while (( NULL != pPreviousPort )
- && ( pPreviousPort->pLinkSocket != pPort )) {
- pPreviousPort = pPreviousPort->pLinkSocket;
- }
- if ( NULL != pPreviousPort ) {
+ pConfig->StationPort = 0;
+ Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )
+ : EFI_SUCCESS;
+ if ( !EFI_ERROR ( Status )) {
//
- // Remove the port from the middle of the socket list
+ // Set the port number
//
- pPreviousPort->pLinkSocket = pPort->pLinkSocket;
- }
- }
+ pConfig->StationPort = SwapBytes16 ( pIpAddress->sin_port );
- //
- // Locate the port in the service list
- //
- pService = pPort->pService;
- pPreviousPort = pService->pPortList;
- if ( pPreviousPort == pPort ) {
- //
- // Remove this port from the head of the service list
- //
- pService->pPortList = pPort->pLinkService;
- }
- else {
- //
- // Locate the port in the middle of the service list
- //
- while (( NULL != pPreviousPort )
- && ( pPreviousPort->pLinkService != pPort )) {
- pPreviousPort = pPreviousPort->pLinkService;
- }
- if ( NULL != pPreviousPort ) {
//
- // Remove the port from the middle of the service list
+ // Display the local address
//
- pPreviousPort->pLinkService = pPort->pLinkService;
- }
- }
-
- //
- // Empty the receive queue
- //
- ASSERT ( NULL == pSocket->pRxPacketListHead );
- ASSERT ( NULL == pSocket->pRxPacketListTail );
- ASSERT ( 0 == pSocket->RxBytes );
-
- //
- // Empty the receive free queue
- //
- while ( NULL != pSocket->pRxFree ) {
- pPacket = pSocket->pRxFree;
- pSocket->pRxFree = pPacket->pNext;
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- }
-
- //
- // Done with the receive event
- //
- pUdp4 = &pPort->Context.Udp4;
- if ( NULL != pUdp4->RxToken.Event ) {
- Status = gBS->CloseEvent ( pUdp4->RxToken.Event );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Closed receive event\r\n",
- pUdp4->RxToken.Event ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close the receive event, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the transmit event
- //
- if ( NULL != pUdp4->TxToken.Event ) {
- Status = gBS->CloseEvent ( pUdp4->TxToken.Event );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Closed normal transmit event\r\n",
- pUdp4->TxToken.Event ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close the normal transmit event, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the UDP protocol
- //
- pUdp4Service = pService->pInterface;
- if ( NULL != pUdp4->pProtocol ) {
- Status = gBS->CloseProtocol ( pUdp4->Handle,
- &gEfiUdp4ProtocolGuid,
- pLayer->ImageHandle,
- NULL );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags,
- "0x%08x: gEfiUdp4ProtocolGuid closed on controller 0x%08x\r\n",
- pUdp4->pProtocol,
- pUdp4->Handle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close gEfiUdp4ProtocolGuid opened on controller 0x%08x, Status: %r\r\n",
- pUdp4->Handle,
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the UDP port
- //
- if ( NULL != pUdp4->Handle ) {
- Status = pUdp4Service->DestroyChild ( pUdp4Service,
- pUdp4->Handle );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Udp4 port handle destroyed\r\n",
- pUdp4->Handle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
- "ERROR - Failed to destroy the Udp4 port handle, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
+ DEBUG (( DEBUG_BIND,
+ "0x%08x: Port, Local UDP4 Address: %d.%d.%d.%d:%d\r\n",
+ pPort,
+ pConfig->StationAddress.Addr[0],
+ pConfig->StationAddress.Addr[1],
+ pConfig->StationAddress.Addr[2],
+ pConfig->StationAddress.Addr[3],
+ pConfig->StationPort ));
}
}
//
- // Release the port structure
- //
- Status = gBS->FreePool ( pPort );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Free pPort, %d bytes\r\n",
- pPort,
- sizeof ( *pPort )));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
- "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
- pPort,
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
-
- //
- // Mark the socket as closed if necessary
- //
- if ( NULL == pSocket->pPortList ) {
- pSocket->State = SOCKET_STATE_CLOSED;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
- pSocket ));
- }
-
- //
// Return the operation status
//
DBG_EXIT_STATUS ( Status );
@@ -651,288 +171,102 @@ EslUdpPortClose4 (
/**
- Start the close operation on a UDP4 port, state 1.
+ Free a receive packet
- Closing a port goes through the following states:
- 1. Port close starting - Mark the port as closing and wait for transmission to complete
- 2. Port TX close done - Transmissions complete, close the port and abort the receives
- 3. Port RX close done - Receive operations complete, close the port
- 4. Port closed - Release the port resources
-
- @param [in] pPort Address of the port structure.
- @param [in] bCloseNow Set TRUE to abort active transfers
- @param [in] DebugFlags Flags for debug messages
+ This routine performs the network specific operations necessary
+ to free a receive packet.
- @retval EFI_SUCCESS The port is closed, not normally returned
- @retval EFI_NOT_READY The port has started the closing process
- @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
- most likely the routine was called already.
+ This routine is called by ::EslSocketPortCloseTxDone to free a
+ receive packet.
+
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
+ @param [in, out] pRxBytes Address of the count of RX bytes
**/
-EFI_STATUS
-EslUdpPortCloseStart4 (
- IN DT_PORT * pPort,
- IN BOOLEAN bCloseNow,
- IN UINTN DebugFlags
+VOID
+EslUdp4PacketFree (
+ IN ESL_PACKET * pPacket,
+ IN OUT size_t * pRxBytes
)
{
- DT_SOCKET * pSocket;
- EFI_STATUS Status;
+ EFI_UDP4_RECEIVE_DATA * pRxData;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
+ // Account for the receive bytes
//
- VERIFY_TPL ( TPL_SOCKETS );
+ pRxData = pPacket->Op.Udp4Rx.pRxData;
+ *pRxBytes -= pRxData->DataLength;
//
- // Mark the port as closing
+ // Disconnect the buffer from the packet
//
- Status = EFI_ALREADY_STARTED;
- pSocket = pPort->pSocket;
- pSocket->errno = EALREADY;
- if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {
-
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_STARTED;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
- pPort ));
- pPort->bCloseNow = bCloseNow;
- pPort->DebugFlags = DebugFlags;
-
- //
- // Determine if transmits are complete
- //
- Status = EslUdpPortCloseTxDone4 ( pPort );
- }
+ pPacket->Op.Udp4Rx.pRxData = NULL;
//
- // Return the operation status
+ // Return the buffer to the UDP4 driver
//
- DBG_EXIT_STATUS ( Status );
- return Status;
+ gBS->SignalEvent ( pRxData->RecycleSignal );
+ DBG_EXIT ( );
}
/**
- Port close state 3
+ Initialize the network specific portions of an ::ESL_PORT structure.
- Continue the close operation after the receive is complete.
+ This routine initializes the network specific portions of an
+ ::ESL_PORT structure for use by the socket.
- @param [in] pPort Address of the port structure.
+ This support routine is called by ::EslSocketPortAllocate
+ to connect the socket with the underlying network adapter
+ running the UDPv4 protocol.
- @retval EFI_SUCCESS The port is closed
- @retval EFI_NOT_READY The port is still closing
- @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
- most likely the routine was called already.
+ @param [in] pPort Address of an ESL_PORT structure
+ @param [in] DebugFlags Flags for debug messages
-**/
+ @retval EFI_SUCCESS - Socket successfully created
+
+ **/
EFI_STATUS
-EslUdpPortCloseRxDone4 (
- IN DT_PORT * pPort
+EslUdp4PortAllocate (
+ IN ESL_PORT * pPort,
+ IN UINTN DebugFlags
)
{
- PORT_STATE PortState;
- DT_SOCKET * pSocket;
- DT_UDP4_CONTEXT * pUdp4;
+ EFI_UDP4_CONFIG_DATA * pConfig;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Verify that the port is closing
+ // Initialize the port
//
- Status = EFI_ALREADY_STARTED;
pSocket = pPort->pSocket;
- pSocket->errno = EALREADY;
- PortState = pPort->State;
- if (( PORT_STATE_CLOSE_TX_DONE == PortState )
- || ( PORT_STATE_CLOSE_DONE == PortState )) {
- //
- // Determine if the receive operation is pending
- //
- Status = EFI_NOT_READY;
- pSocket->errno = EAGAIN;
- pUdp4 = &pPort->Context.Udp4;
- if ( NULL == pUdp4->pReceivePending ) {
- //
- // The receive operation is complete
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_RX_DONE;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
- pPort ));
-
- //
- // The close operation has completed
- // Release the port resources
- //
- Status = EslUdpPortClose4 ( pPort );
- }
- else {
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close: Receive still pending!\r\n",
- pPort ));
- }
- }
+ pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Udp4Tx.TxData );
+ pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Tx.Event );
+ pSocket->TxTokenOffset = OFFSET_OF ( EFI_UDP4_COMPLETION_TOKEN, Packet.TxData );
//
- // Return the operation status
+ // Save the cancel, receive and transmit addresses
//
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Port close state 2
-
- Continue the close operation after the transmission is complete.
-
- @param [in] pPort Address of the port structure.
-
- @retval EFI_SUCCESS The port is closed, not normally returned
- @retval EFI_NOT_READY The port is still closing
- @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
- most likely the routine was called already.
-
-**/
-EFI_STATUS
-EslUdpPortCloseTxDone4 (
- IN DT_PORT * pPort
- )
-{
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_UDP4_PROTOCOL * pUdp4Protocol;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
+ pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.UDPv4->Configure;
+ pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Cancel;
+ pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Receive;
+ pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Transmit;
//
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
+ // Set the configuration flags
//
- // All transmissions are complete or must be stopped
- // Mark the port as TX complete
- //
- Status = EFI_ALREADY_STARTED;
- if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {
- //
- // Verify that the transmissions are complete
- //
- pSocket = pPort->pSocket;
- if ( pPort->bCloseNow
- || ( EFI_SUCCESS != pSocket->TxError )
- || ( 0 == pSocket->TxBytes )) {
- //
- // Start the close operation on the port
- //
- pUdp4 = &pPort->Context.Udp4;
- pUdp4Protocol = pUdp4->pProtocol;
- if ( !pUdp4->bConfigured ) {
- //
- // Skip the close operation since the port is not
- // configured
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_DONE;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
- pPort ));
- Status = EFI_SUCCESS;
- }
- else {
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_TX_DONE;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
- pPort ));
-
- //
- // Empty the receive queue
- //
- while ( NULL != pSocket->pRxPacketListHead ) {
- pPacket = pSocket->pRxPacketListHead;
- pSocket->pRxPacketListHead = pPacket->pNext;
- pSocket->RxBytes -= pPacket->Op.Udp4Rx.pRxData->DataLength;
-
- //
- // Return the buffer to the UDP4 driver
- //
- gBS->SignalEvent ( pPacket->Op.Udp4Rx.pRxData->RecycleSignal );
-
- //
- // Done with this packet
- //
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- }
- pSocket->pRxPacketListTail = NULL;
- ASSERT ( 0 == pSocket->RxBytes );
-
- //
- // Reset the port, cancel the outstanding receive
- //
- Status = pUdp4Protocol->Configure ( pUdp4Protocol,
- NULL );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port reset\r\n",
- pPort ));
-
- //
- // Free the receive packet
- //
- Status = gBS->CheckEvent ( pUdp4->RxToken.Event );
- if ( EFI_SUCCESS != Status ) {
- EslSocketPacketFree ( pUdp4->pReceivePending, DEBUG_CLOSE );
- pUdp4->pReceivePending = NULL;
- Status = EFI_SUCCESS;
- }
- }
- else {
- DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
- "ERROR - Port 0x%08x reset failed, Status: %r\r\n",
- pPort,
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Determine if the receive operation is pending
- //
- if ( !EFI_ERROR ( Status )) {
- Status = EslUdpPortCloseRxDone4 ( pPort );
- }
- }
- else {
- //
- // Transmissions are still active, exit
- //
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close: Transmits are still pending!\r\n",
- pPort ));
- Status = EFI_NOT_READY;
- pSocket->errno = EAGAIN;
- }
- }
+ pConfig = &pPort->Context.Udp4.ConfigData;
+ pConfig->TimeToLive = 255;
+ pConfig->AcceptAnyPort = FALSE;
+ pConfig->AcceptBroadcast = FALSE;
+ pConfig->AcceptPromiscuous = FALSE;
+ pConfig->AllowDuplicatePort = TRUE;
+ pConfig->DoNotFragment = TRUE;
+ Status = EFI_SUCCESS;
//
// Return the operation status
@@ -943,603 +277,192 @@ EslUdpPortCloseTxDone4 (
/**
- Connect to a remote system via the network.
+ Receive data from a network connection.
- The ::UdpConnectStart4= routine sets the remote address for the connection.
+ This routine attempts to return buffered data to the caller. The
+ data is removed from the urgent queue if the message flag MSG_OOB
+ is specified, otherwise data is removed from the normal queue.
+ See the \ref ReceiveEngine section.
- @param [in] pSocket Address of the socket structure.
+ This routine is called by ::EslSocketReceive to handle the network
+ specific receive operation to support SOCK_DGRAM sockets.
- @param [in] pSockAddr Network address of the remote system.
-
- @param [in] SockAddrLength Length in bytes of the network address.
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
+
+ @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
- @retval EFI_SUCCESS The connection was successfully established.
- @retval EFI_NOT_READY The connection is in progress, call this routine again.
- @retval Others The connection attempt failed.
+ @param [in] BufferLength Length of the the buffer
+
+ @param [in] pBuffer Address of a buffer to receive the data.
+
+ @param [in] pDataLength Number of received data bytes in the buffer.
+
+ @param [out] pAddress Network address to receive the remote system address
+
+ @param [out] pSkipBytes Address to receive the number of bytes skipped
+
+ @return Returns the address of the next free byte in the buffer.
**/
-EFI_STATUS
-EslUdpConnect4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
+UINT8 *
+EslUdp4Receive (
+ IN ESL_PORT * pPort,
+ IN ESL_PACKET * pPacket,
+ IN BOOLEAN * pbConsumePacket,
+ IN size_t BufferLength,
+ IN UINT8 * pBuffer,
+ OUT size_t * pDataLength,
+ OUT struct sockaddr * pAddress,
+ OUT size_t * pSkipBytes
)
{
- struct sockaddr_in LocalAddress;
- DT_PORT * pPort;
+ size_t DataBytes;
struct sockaddr_in * pRemoteAddress;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_STATUS Status;
+ EFI_UDP4_RECEIVE_DATA * pRxData;
DBG_ENTER ( );
+ pRxData = pPacket->Op.Udp4Rx.pRxData;
//
- // Assume failure
- //
- Status = EFI_NETWORK_UNREACHABLE;
- pSocket->errno = ENETUNREACH;
-
+ // Return the remote system address if requested
//
- // Get the address
- //
- pRemoteAddress = (struct sockaddr_in *)pSockAddr;
-
- //
- // Validate the address length
- //
- if ( SockAddrLength >= ( sizeof ( *pRemoteAddress )
- - sizeof ( pRemoteAddress->sin_zero ))) {
- //
- // Determine if BIND was already called
- //
- if ( NULL == pSocket->pPortList ) {
- //
- // Allow any local port
- //
- ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
- LocalAddress.sin_len = sizeof ( LocalAddress );
- LocalAddress.sin_family = AF_INET;
- Status = EslSocketBind ( &pSocket->SocketProtocol,
- (struct sockaddr *)&LocalAddress,
- LocalAddress.sin_len,
- &pSocket->errno );
- }
-
+ if ( NULL != pAddress ) {
//
- // Walk the list of ports
+ // Build the remote address
//
- pPort = pSocket->pPortList;
- while ( NULL != pPort ) {
- //
- // Set the remote address
- //
- pUdp4 = &pPort->Context.Udp4;
- pUdp4->ConfigData.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
- pUdp4->ConfigData.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
- pUdp4->ConfigData.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
- pUdp4->ConfigData.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
- pUdp4->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );
-
- //
- // At least one path exists
- //
- Status = EFI_SUCCESS;
- pSocket->errno = 0;
-
- //
- // Set the next port
- //
- pPort = pPort->pLinkSocket;
- }
- }
- else {
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid UDP4 address length: %d\r\n",
- SockAddrLength ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
+ DEBUG (( DEBUG_RX,
+ "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
+ pRxData->UdpSession.SourceAddress.Addr[0],
+ pRxData->UdpSession.SourceAddress.Addr[1],
+ pRxData->UdpSession.SourceAddress.Addr[2],
+ pRxData->UdpSession.SourceAddress.Addr[3],
+ pRxData->UdpSession.SourcePort ));
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pRxData->UdpSession.SourceAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_addr ));
+ pRemoteAddress->sin_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );
}
//
- // Return the connect status
+ // Copy the received data
//
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Get the local socket address
-
- @param [in] pSocket Address of the socket structure.
-
- @param [out] pAddress Network address to receive the local system address
-
- @param [in,out] pAddressLength Length of the local network address structure
-
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
-
-**/
-EFI_STATUS
-EslUdpGetLocalAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
- )
-{
- socklen_t LengthInBytes;
- DT_PORT * pPort;
- struct sockaddr_in * pLocalAddress;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
+ pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount,
+ (EFI_IP4_FRAGMENT_DATA *)&pRxData->FragmentTable[0],
+ BufferLength,
+ pBuffer,
+ &DataBytes );
//
- // Verify the socket layer synchronization
+ // Determine if the data is being read
//
- VERIFY_TPL ( TPL_SOCKETS );
+ if ( *pbConsumePacket ) {
+ //
+ // Display for the bytes consumed
+ //
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port account for 0x%08x bytes\r\n",
+ pPort,
+ DataBytes ));
- //
- // Verify that there is just a single connection
- //
- pPort = pSocket->pPortList;
- if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
//
- // Verify the address length
+ // Account for any discarded data
//
- LengthInBytes = sizeof ( struct sockaddr_in );
- if ( LengthInBytes <= * pAddressLength ) {
- //
- // Return the local address
- //
- pUdp4 = &pPort->Context.Udp4;
- pLocalAddress = (struct sockaddr_in *)pAddress;
- ZeroMem ( pLocalAddress, LengthInBytes );
- pLocalAddress->sin_family = AF_INET;
- pLocalAddress->sin_len = (uint8_t)LengthInBytes;
- pLocalAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.StationPort );
- CopyMem ( &pLocalAddress->sin_addr,
- &pUdp4->ConfigData.StationAddress.Addr[0],
- sizeof ( pLocalAddress->sin_addr ));
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
- }
- else {
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
- }
+ *pSkipBytes = pRxData->DataLength - DataBytes;
}
- else {
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
- }
-
+
//
- // Return the operation status
+ // Return the data length and the buffer address
//
- DBG_EXIT_STATUS ( Status );
- return Status;
+ *pDataLength = DataBytes;
+ DBG_EXIT_HEX ( pBuffer );
+ return pBuffer;
}
/**
Get the remote socket address
- @param [in] pSocket Address of the socket structure.
+ This routine returns the address of the remote connection point
+ associated with the SOCK_DGRAM socket.
- @param [out] pAddress Network address to receive the remote system address
+ This routine is called by ::EslSocketGetPeerAddress to detemine
+ the UDPv4 address and port number associated with the network adapter.
- @param [in,out] pAddressLength Length of the remote network address structure
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
+ @param [out] pAddress Network address to receive the remote system address
**/
-EFI_STATUS
-EslUdpGetRemoteAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+VOID
+EslUdp4RemoteAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
)
{
- socklen_t LengthInBytes;
- DT_PORT * pPort;
struct sockaddr_in * pRemoteAddress;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_STATUS Status;
+ ESL_UDP4_CONTEXT * pUdp4;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
+ // Return the remote address
//
- VERIFY_TPL ( TPL_SOCKETS );
+ pUdp4 = &pPort->Context.Udp4;
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ pRemoteAddress->sin_family = AF_INET;
+ pRemoteAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.RemotePort );
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pUdp4->ConfigData.RemoteAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_addr ));
- //
- // Verify that there is just a single connection
- //
- pPort = pSocket->pPortList;
- if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
- //
- // Verify the address length
- //
- LengthInBytes = sizeof ( struct sockaddr_in );
- if ( LengthInBytes <= * pAddressLength ) {
- //
- // Return the local address
- //
- pUdp4 = &pPort->Context.Udp4;
- pRemoteAddress = (struct sockaddr_in *)pAddress;
- ZeroMem ( pRemoteAddress, LengthInBytes );
- pRemoteAddress->sin_family = AF_INET;
- pRemoteAddress->sin_len = (uint8_t)LengthInBytes;
- pRemoteAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.RemotePort );
- CopyMem ( &pRemoteAddress->sin_addr,
- &pUdp4->ConfigData.RemoteAddress.Addr[0],
- sizeof ( pRemoteAddress->sin_addr ));
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
- }
- else {
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
- }
- }
- else {
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
- }
-
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
+ DBG_EXIT ( );
}
/**
- Receive data from a network connection.
-
- To minimize the number of buffer copies, the ::UdpRxComplete4
- routine queues the UDP4 driver's buffer to a list of datagrams
- waiting to be received. The socket driver holds on to the
- buffers from the UDP4 driver until the application layer requests
- the data or the socket is closed.
-
- The application calls this routine in the socket layer to
- receive datagrams from one or more remote systems. This routine
- removes the next available datagram from the list of datagrams
- and copies the data from the UDP4 driver's buffer into the
- application's buffer. The UDP4 driver's buffer is then returned.
-
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @param [in] Flags Message control flags
-
- @param [in] BufferLength Length of the the buffer
+ Set the remote address
- @param [in] pBuffer Address of a buffer to receive the data.
+ This routine sets the remote address in the port.
- @param [in] pDataLength Number of received data bytes in the buffer.
+ This routine is called by ::EslSocketConnect to specify the
+ remote network address.
- @param [out] pAddress Network address to receive the remote system address
-
- @param [in,out] pAddressLength Length of the remote network address structure
-
- @retval EFI_SUCCESS - Socket data successfully received
-
-**/
-EFI_STATUS
-EslUdpReceive4 (
- IN DT_SOCKET * pSocket,
- IN INT32 Flags,
- IN size_t BufferLength,
- IN UINT8 * pBuffer,
- OUT size_t * pDataLength,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
- )
-{
- socklen_t AddressLength;
- size_t BytesToCopy;
- size_t DataBytes;
- UINT32 Fragment;
- in_addr_t IpAddress;
- size_t LengthInBytes;
- UINT8 * pData;
- DT_PACKET * pPacket;
- DT_PORT * pPort;
- struct sockaddr_in * pRemoteAddress;
- EFI_UDP4_RECEIVE_DATA * pRxData;
- DT_UDP4_CONTEXT * pUdp4;
- struct sockaddr_in RemoteAddress;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Assume failure
- //
- Status = EFI_UNSUPPORTED;
- pSocket->errno = ENOTCONN;
-
- //
- // Verify that the socket is connected
- //
- if (( SOCKET_STATE_CONNECTED == pSocket->State )
- || ( PORT_STATE_RX_ERROR == pSocket->State )) {
- //
- // Locate the port
- //
- pPort = pSocket->pPortList;
- if ( NULL != pPort ) {
- //
- // Determine if there is any data on the queue
- //
- pUdp4 = &pPort->Context.Udp4;
- pPacket = pSocket->pRxPacketListHead;
- if ( NULL != pPacket ) {
- //
- // Validate the return address parameters
- //
- pRxData = pPacket->Op.Udp4Rx.pRxData;
- if (( NULL == pAddress ) || ( NULL != pAddressLength )) {
- //
- // Return the remote system address if requested
- //
- if ( NULL != pAddress ) {
- //
- // Build the remote address
- //
- DEBUG (( DEBUG_RX,
- "Getting packet source address: %d.%d.%d.%d:%d\r\n",
- pRxData->UdpSession.SourceAddress.Addr[0],
- pRxData->UdpSession.SourceAddress.Addr[1],
- pRxData->UdpSession.SourceAddress.Addr[2],
- pRxData->UdpSession.SourceAddress.Addr[3],
- pRxData->UdpSession.SourcePort ));
- ZeroMem ( &RemoteAddress, sizeof ( RemoteAddress ));
- RemoteAddress.sin_len = sizeof ( RemoteAddress );
- RemoteAddress.sin_family = AF_INET;
- IpAddress = pRxData->UdpSession.SourceAddress.Addr[3];
- IpAddress <<= 8;
- IpAddress |= pRxData->UdpSession.SourceAddress.Addr[2];
- IpAddress <<= 8;
- IpAddress |= pRxData->UdpSession.SourceAddress.Addr[1];
- IpAddress <<= 8;
- IpAddress |= pRxData->UdpSession.SourceAddress.Addr[0];
- RemoteAddress.sin_addr.s_addr = IpAddress;
- RemoteAddress.sin_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );
-
- //
- // Copy the address
- //
- pRemoteAddress = (struct sockaddr_in *)pAddress;
- AddressLength = sizeof ( *pRemoteAddress );
- if ( AddressLength > *pAddressLength ) {
- AddressLength = *pAddressLength;
- }
- CopyMem ( pRemoteAddress,
- &RemoteAddress,
- AddressLength );
-
- //
- // Update the address length
- //
- *pAddressLength = AddressLength;
- }
-
- //
- // Reduce the buffer length if necessary
- //
- DataBytes = pRxData->DataLength;
- if ( DataBytes < BufferLength ) {
- BufferLength = DataBytes;
- }
-
- //
- // Copy the received data
- //
- LengthInBytes = 0;
- Fragment = 0;
- do {
- //
- // Determine the amount of received data
- //
- pData = pRxData->FragmentTable[Fragment].FragmentBuffer;
- BytesToCopy = pRxData->FragmentTable[Fragment].FragmentLength;
- if (( BufferLength - LengthInBytes ) < BytesToCopy ) {
- BytesToCopy = BufferLength - LengthInBytes;
- }
- LengthInBytes += BytesToCopy;
-
- //
- // Move the data into the buffer
- //
- DEBUG (( DEBUG_RX,
- "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
- pPort,
- pPacket,
- pBuffer,
- BytesToCopy ));
- CopyMem ( pBuffer, pData, BytesToCopy );
- } while ( BufferLength > LengthInBytes );
-
- //
- // Determine if the data is being read
- //
- if ( 0 == ( Flags & MSG_PEEK )) {
- //
- // Display for the bytes consumed
- //
- DEBUG (( DEBUG_RX,
- "0x%08x: Port account for 0x%08x bytes\r\n",
- pPort,
- BufferLength ));
-
- //
- // All done with this packet
- // Account for any discarded data
- //
- pSocket->RxBytes -= DataBytes;
- if ( 0 != ( DataBytes - BufferLength )) {
- DEBUG (( DEBUG_RX,
- "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
- pPort,
- DataBytes - BufferLength ));
- }
-
- //
- // Remove this packet from the queue
- //
- pSocket->pRxPacketListHead = pPacket->pNext;
- if ( NULL == pSocket->pRxPacketListHead ) {
- pSocket->pRxPacketListTail = NULL;
- }
-
- //
- // Return this packet to the UDP4 driver
- //
- gBS->SignalEvent ( pRxData->RecycleSignal );
-
- //
- // Move the packet to the free queue
- //
- pPacket->pNext = pSocket->pRxFree;
- pSocket->pRxFree = pPacket;
- DEBUG (( DEBUG_RX,
- "0x%08x: Port freeing packet 0x%08x\r\n",
- pPort,
- pPacket ));
-
- //
- // Restart this receive operation if necessary
- //
- if (( NULL == pUdp4->pReceivePending )
- && ( MAX_RX_DATA > pSocket->RxBytes )) {
- EslUdpRxStart4 ( pPort );
- }
- }
-
- //
- // Return the data length
- //
- *pDataLength = LengthInBytes;
-
- //
- // Successful operation
- //
- Status = EFI_SUCCESS;
- pSocket->errno = 0;
- }
- else {
- //
- // Bad return address pointer and length
- //
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
- }
- }
- else {
- //
- // The queue is empty
- // Determine if it is time to return the receive error
- //
- if ( EFI_ERROR ( pSocket->RxError )) {
- Status = pSocket->RxError;
- switch ( Status ) {
- default:
- pSocket->errno = EIO;
- break;
-
- case EFI_HOST_UNREACHABLE:
- pSocket->errno = EHOSTUNREACH;
- break;
-
- case EFI_NETWORK_UNREACHABLE:
- pSocket->errno = ENETUNREACH;
- break;
-
- case EFI_PORT_UNREACHABLE:
- pSocket->errno = EPROTONOSUPPORT;
- break;
-
- case EFI_PROTOCOL_UNREACHABLE:
- pSocket->errno = ENOPROTOOPT;
- break;
- }
- pSocket->RxError = EFI_SUCCESS;
- }
- else {
- Status = EFI_NOT_READY;
- pSocket->errno = EAGAIN;
- }
- }
- }
- }
-
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
+ @param [in] pPort Address of an ::ESL_PORT structure.
+ @param [in] pSockAddr Network address of the remote system.
-/**
- Cancel the receive operations
+ @param [in] SockAddrLength Length in bytes of the network address.
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @retval EFI_SUCCESS - The cancel was successful
+ @retval EFI_SUCCESS The operation was successful
**/
EFI_STATUS
-EslUdpRxCancel4 (
- IN DT_SOCKET * pSocket
+EslUdp4RemoteAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN socklen_t SockAddrLength
)
{
- DT_PACKET * pPacket;
- DT_PORT * pPort;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_UDP4_PROTOCOL * pUdp4Protocol;
+ CONST struct sockaddr_in * pRemoteAddress;
+ ESL_UDP4_CONTEXT * pUdp4;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Assume failure
- //
- Status = EFI_NOT_FOUND;
-
+ // Set the remote address
//
- // Locate the port
- //
- pPort = pSocket->pPortList;
- if ( NULL != pPort ) {
- //
- // Determine if a receive is pending
- //
- pUdp4 = &pPort->Context.Udp4;
- pPacket = pUdp4->pReceivePending;
- if ( NULL != pPacket ) {
- //
- // Attempt to cancel the receive operation
- //
- pUdp4Protocol = pUdp4->pProtocol;
- Status = pUdp4Protocol->Cancel ( pUdp4Protocol,
- &pUdp4->RxToken );
- if ( EFI_NOT_FOUND == Status ) {
- //
- // The receive is complete
- //
- Status = EFI_SUCCESS;
- }
- }
- }
+ pUdp4 = &pPort->Context.Udp4;
+ pRemoteAddress = (struct sockaddr_in *)pSockAddr;
+ pUdp4->ConfigData.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
+ pUdp4->ConfigData.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
+ pUdp4->ConfigData.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
+ pUdp4->ConfigData.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
+ pUdp4->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );
+ Status = EFI_SUCCESS;
//
// Return the operation status
@@ -1552,351 +475,102 @@ EslUdpRxCancel4 (
/**
Process the receive completion
- Keep the UDP4 driver's buffer and append it to the list of
- datagrams for the application to receive. The UDP4 driver's
- buffer will be returned by either ::UdpReceive4 or
- ::UdpPortCloseTxDone4.
+ This routine keeps the UDPv4 driver's buffer and queues it in
+ in FIFO order to the data queue. The UDP4 driver's buffer will
+ be returned by either ::EslUdp4Receive or ::EslSocketPortCloseTxDone.
+ See the \ref ReceiveEngine section.
- @param Event The receive completion event
+ This routine is called by the UDPv4 driver when data is
+ received.
- @param pPort The DT_PORT structure address
+ @param [in] Event The receive completion event
+
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
**/
VOID
-EslUdpRxComplete4 (
+EslUdp4RxComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_IO_MGMT * pIo
)
{
size_t LengthInBytes;
- DT_PACKET * pPacket;
- DT_PACKET * pPrevious;
+ ESL_PACKET * pPacket;
EFI_UDP4_RECEIVE_DATA * pRxData;
- DT_SOCKET * pSocket;
- DT_UDP4_CONTEXT * pUdp4;
EFI_STATUS Status;
DBG_ENTER ( );
-
- //
- // Mark this receive complete
- //
- pUdp4 = &pPort->Context.Udp4;
- pPacket = pUdp4->pReceivePending;
- pUdp4->pReceivePending = NULL;
-
+
//
- // Determine if this receive was successful
+ // Get the operation status.
//
- pSocket = pPort->pSocket;
- Status = pUdp4->RxToken.Status;
- if (( !EFI_ERROR ( Status )) && ( !pSocket->bRxDisable )) {
- pRxData = pUdp4->RxToken.Packet.RxData;
- if ( PORT_STATE_CLOSE_STARTED >= pPort->State ) {
- //
- // Save the data in the packet
- //
- pPacket->Op.Udp4Rx.pRxData = pRxData;
-
- //
- // Queue this packet
- //
- pPrevious = pSocket->pRxPacketListTail;
- if ( NULL == pPrevious ) {
- pSocket->pRxPacketListHead = pPacket;
- }
- else {
- pPrevious->pNext = pPacket;
- }
- pSocket->pRxPacketListTail = pPacket;
-
- //
- // Account for the normal data
- //
- LengthInBytes = pRxData->DataLength;
- pSocket->RxBytes += LengthInBytes;
-
- //
- // Log the received data
- //
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "Received packet from: %d.%d.%d.%d:%d\r\n",
- pRxData->UdpSession.SourceAddress.Addr[0],
- pRxData->UdpSession.SourceAddress.Addr[1],
- pRxData->UdpSession.SourceAddress.Addr[2],
- pRxData->UdpSession.SourceAddress.Addr[3],
- pRxData->UdpSession.SourcePort ));
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "Received packet sent to: %d.%d.%d.%d:%d\r\n",
- pRxData->UdpSession.DestinationAddress.Addr[0],
- pRxData->UdpSession.DestinationAddress.Addr[1],
- pRxData->UdpSession.DestinationAddress.Addr[2],
- pRxData->UdpSession.DestinationAddress.Addr[3],
- pRxData->UdpSession.DestinationPort ));
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "0x%08x: Packet queued on port 0x%08x with 0x%08x bytes of data\r\n",
- pPacket,
- pPort,
- LengthInBytes ));
-
- //
- // Attempt to restart this receive operation
- //
- if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
- EslUdpRxStart4 ( pPort );
- }
- else {
- DEBUG (( DEBUG_RX,
- "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
- pPort,
- pSocket->RxBytes ));
- }
- }
- else {
- //
- // The port is being closed
- // Return the buffer to the UDP4 driver
- //
- gBS->SignalEvent ( pRxData->RecycleSignal );
-
- //
- // Free the packet
- //
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- }
- }
- else
- {
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "ERROR - Receiving packet 0x%08x, on port 0x%08x, Status:%r\r\n",
- pPacket,
- pPort,
- Status ));
-
- //
- // Receive error, free the packet save the error
- //
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- if ( !EFI_ERROR ( pSocket->RxError )) {
- pSocket->RxError = Status;
- }
-
- //
- // Update the port state
- //
- if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
- EslUdpPortCloseRxDone4 ( pPort );
- }
- else {
- if ( EFI_ERROR ( Status )) {
- pPort->State = PORT_STATE_RX_ERROR;
- }
- }
- }
+ Status = pIo->Token.Udp4Rx.Status;
- DBG_EXIT ( );
-}
-
-
-/**
- Start a receive operation
-
- @param [in] pPort Address of the DT_PORT structure.
-
- **/
-VOID
-EslUdpRxStart4 (
- IN DT_PORT * pPort
- )
-{
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_UDP4_PROTOCOL * pUdp4Protocol;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
//
- // Determine if a receive is already pending
+ // Get the packet length
//
- Status = EFI_SUCCESS;
- pPacket = NULL;
- pSocket = pPort->pSocket;
- pUdp4 = &pPort->Context.Udp4;
- if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
- if (( NULL == pUdp4->pReceivePending )
- && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
- //
- // Determine if there are any free packets
- //
- pPacket = pSocket->pRxFree;
- if ( NULL != pPacket ) {
- //
- // Remove this packet from the free list
- //
- pSocket->pRxFree = pPacket->pNext;
- DEBUG (( DEBUG_RX,
- "0x%08x: Port removed packet 0x%08x from free list\r\n",
- pPort,
- pPacket ));
- }
- else {
- //
- // Allocate a packet structure
- //
- Status = EslSocketPacketAllocate ( &pPacket,
- sizeof ( pPacket->Op.Udp4Rx ),
- DEBUG_RX );
- if ( EFI_ERROR ( Status )) {
- pPacket = NULL;
- DEBUG (( DEBUG_ERROR | DEBUG_RX,
- "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
- pPort,
- Status ));
- }
- }
-
- //
- // Determine if a packet is available
- //
- if ( NULL != pPacket ) {
- //
- // Initialize the buffer for receive
- //
- pPacket->pNext = NULL;
- pPacket->Op.Udp4Rx.pRxData = NULL;
- pUdp4->RxToken.Packet.RxData = NULL;
- pUdp4->pReceivePending = pPacket;
-
- //
- // Start the receive on the packet
- //
- pUdp4Protocol = pUdp4->pProtocol;
- Status = pUdp4Protocol->Receive ( pUdp4Protocol,
- &pUdp4->RxToken );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "0x%08x: Packet receive pending on port 0x%08x\r\n",
- pPacket,
- pPort ));
- }
- else {
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
- pPort,
- Status ));
- if ( !EFI_ERROR ( pSocket->RxError )) {
- //
- // Save the error status
- //
- pSocket->RxError = Status;
- }
-
- //
- // Free the packet
- //
- pUdp4->pReceivePending = NULL;
- pPacket->pNext = pSocket->pRxFree;
- pSocket->pRxFree = pPacket;
- }
- }
- }
- }
-
- DBG_EXIT ( );
-}
-
-
-/**
- Shutdown the UDP4 service.
-
- This routine undoes the work performed by ::UdpInitialize4.
-
- @param [in] pService DT_SERVICE structure address
-
-**/
-VOID
-EFIAPI
-EslUdpShutdown4 (
- IN DT_SERVICE * pService
- )
-{
- DT_LAYER * pLayer;
- DT_PORT * pPort;
- DT_SERVICE * pPreviousService;
-
- DBG_ENTER ( );
+ pRxData = pIo->Token.Udp4Rx.Packet.RxData;
+ LengthInBytes = pRxData->DataLength;
//
- // Verify the socket layer synchronization
+ // +--------------------+ +-----------------------+
+ // | ESL_IO_MGMT | | Data Buffer |
+ // | | | (Driver owned) |
+ // | +---------------+ +-----------------------+
+ // | | Token | ^
+ // | | Rx Event | |
+ // | | | +-----------------------+
+ // | | RxData --> | EFI_UDP4_RECEIVE_DATA |
+ // +----+---------------+ | (Driver owned) |
+ // +-----------------------+
+ // +--------------------+ ^
+ // | ESL_PACKET | .
+ // | | .
+ // | +---------------+ .
+ // | | pRxData --> NULL .......
+ // +----+---------------+
//
- VERIFY_TPL ( TPL_SOCKETS );
-
//
- // Walk the list of ports
+ // Save the data in the packet
//
- do {
- pPort = pService->pPortList;
- if ( NULL != pPort ) {
- //
- // Remove the port from the port list
- //
- pService->pPortList = pPort->pLinkService;
-
- //
- // Close the port
- // TODO: Fix this
- //
-// pPort->pfnClosePort ( pPort, 0 );
- }
- } while ( NULL != pPort );
+ pPacket = pIo->pPacket;
+ pPacket->Op.Udp4Rx.pRxData = pRxData;
//
- // Remove the service from the service list
+ // Complete this request
//
- pLayer = &mEslLayer;
- pPreviousService = pLayer->pUdp4List;
- if ( pService == pPreviousService ) {
- //
- // Remove the service from the beginning of the list
- //
- pLayer->pUdp4List = pService->pNext;
- }
- else {
- //
- // Remove the service from the middle of the list
- //
- while ( NULL != pPreviousService ) {
- if ( pService == pPreviousService->pNext ) {
- pPreviousService->pNext = pService->pNext;
- break;
- }
- }
- }
-
+ EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE );
DBG_EXIT ( );
}
/**
- Determine if the sockedt is configured.
+ Determine if the socket is configured.
+ This routine uses the flag ESL_SOCKET::bConfigured to determine
+ if the network layer's configuration routine has been called.
+ This routine calls the bind and configuration routines if they
+ were not already called. After the port is configured, the
+ \ref ReceiveEngine is started.
+
+ This routine is called by EslSocketIsConfigured to verify
+ that the socket is configured.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
- @param [in] pSocket Address of a DT_SOCKET structure
-
@retval EFI_SUCCESS - The port is connected
@retval EFI_NOT_STARTED - The port is not connected
**/
EFI_STATUS
- EslUdpSocketIsConfigured4 (
- IN DT_SOCKET * pSocket
+ EslUdp4SocketIsConfigured (
+ IN ESL_SOCKET * pSocket
)
{
- DT_PORT * pPort;
- DT_PORT * pNextPort;
- DT_UDP4_CONTEXT * pUdp4;
+ EFI_UDP4_CONFIG_DATA * pConfigData;
+ ESL_PORT * pPort;
+ ESL_PORT * pNextPort;
+ ESL_UDP4_CONTEXT * pUdp4;
EFI_UDP4_PROTOCOL * pUdp4Protocol;
EFI_STATUS Status;
struct sockaddr_in LocalAddress;
@@ -1920,9 +594,10 @@ EslUdpShutdown4 (
LocalAddress.sin_family = AF_INET;
LocalAddress.sin_addr.s_addr = 0;
LocalAddress.sin_port = 0;
- Status = EslUdpBind4 ( pSocket,
- (struct sockaddr *)&LocalAddress,
- LocalAddress.sin_len );
+ Status = EslSocketBind ( &pSocket->SocketProtocol,
+ (struct sockaddr *)&LocalAddress,
+ LocalAddress.sin_len,
+ &pSocket->errno );
}
//
@@ -1935,9 +610,33 @@ EslUdpShutdown4 (
//
pNextPort = pPort->pLinkSocket;
pUdp4 = &pPort->Context.Udp4;
- pUdp4Protocol = pUdp4->pProtocol;
+ pUdp4Protocol = pPort->pProtocol.UDPv4;
+ pConfigData = &pUdp4->ConfigData;
+ DEBUG (( DEBUG_TX,
+ "0x%08x: pPort Configuring for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",
+ pPort,
+ pConfigData->StationAddress.Addr[0],
+ pConfigData->StationAddress.Addr[1],
+ pConfigData->StationAddress.Addr[2],
+ pConfigData->StationAddress.Addr[3],
+ pConfigData->StationPort,
+ pConfigData->RemoteAddress.Addr[0],
+ pConfigData->RemoteAddress.Addr[1],
+ pConfigData->RemoteAddress.Addr[2],
+ pConfigData->RemoteAddress.Addr[3],
+ pConfigData->RemotePort ));
Status = pUdp4Protocol->Configure ( pUdp4Protocol,
- &pUdp4->ConfigData );
+ pConfigData );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Update the configuration data
+ //
+ Status = pUdp4Protocol->GetModeData ( pUdp4Protocol,
+ pConfigData,
+ NULL,
+ NULL,
+ NULL );
+ }
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_LISTEN,
"ERROR - Failed to configure the Udp4 port, Status: %r\r\n",
@@ -1970,15 +669,25 @@ EslUdpShutdown4 (
}
}
else {
- DEBUG (( DEBUG_LISTEN,
- "0x%08x: Port configured\r\n",
- pPort ));
- pUdp4->bConfigured = TRUE;
+ DEBUG (( DEBUG_TX,
+ "0x%08x: pPort Configured for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",
+ pPort,
+ pConfigData->StationAddress.Addr[0],
+ pConfigData->StationAddress.Addr[1],
+ pConfigData->StationAddress.Addr[2],
+ pConfigData->StationAddress.Addr[3],
+ pConfigData->StationPort,
+ pConfigData->RemoteAddress.Addr[0],
+ pConfigData->RemoteAddress.Addr[1],
+ pConfigData->RemoteAddress.Addr[2],
+ pConfigData->RemoteAddress.Addr[3],
+ pConfigData->RemotePort ));
+ pPort->bConfigured = TRUE;
//
// Start the first read on the port
//
- EslUdpRxStart4 ( pPort );
+ EslSocketRxStart ( pPort );
//
// The socket is connected
@@ -2018,10 +727,15 @@ EslUdpShutdown4 (
/**
Buffer data for transmission over a network connection.
- This routine is called by the socket layer API to buffer
+ This routine buffers data for the transmit engine in the normal
+ data queue. When the \ref TransmitEngine has resources, this
+ routine will start the transmission of the next buffer on the
+ network connection.
+
+ This routine is called by ::EslSocketTransmit to buffer
data for transmission. The data is copied into a local buffer
freeing the application buffer for reuse upon return. When
- necessary, this routine will start the transmit engine that
+ necessary, this routine starts the transmit engine that
performs the data transmission on the network connection. The
transmit engine transmits the data a packet at a time over the
network connection.
@@ -2030,7 +744,7 @@ EslUdpShutdown4 (
during the close operation. Only buffering errors are returned
during the current transmission attempt.
- @param [in] pSocket Address of a DT_SOCKET structure
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
@param [in] Flags Message control flags
@@ -2048,8 +762,8 @@ EslUdpShutdown4 (
**/
EFI_STATUS
-EslUdpTxBuffer4 (
- IN DT_SOCKET * pSocket,
+EslUdp4TxBuffer (
+ IN ESL_SOCKET * pSocket,
IN int Flags,
IN size_t BufferLength,
IN CONST UINT8 * pBuffer,
@@ -2058,15 +772,13 @@ EslUdpTxBuffer4 (
IN socklen_t AddressLength
)
{
- DT_PACKET * pPacket;
- DT_PACKET * pPreviousPacket;
- DT_PACKET ** ppPacket;
- DT_PORT * pPort;
+ ESL_PACKET * pPacket;
+ ESL_PACKET * pPreviousPacket;
+ ESL_PORT * pPort;
const struct sockaddr_in * pRemoteAddress;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_UDP4_COMPLETION_TOKEN * pToken;
+ ESL_UDP4_CONTEXT * pUdp4;
size_t * pTxBytes;
- DT_UDP4_TX_DATA * pTxData;
+ ESL_UDP4_TX_DATA * pTxData;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -2077,7 +789,7 @@ EslUdpTxBuffer4 (
//
Status = EFI_UNSUPPORTED;
pSocket->errno = ENOTCONN;
- * pDataLength = 0;
+ *pDataLength = 0;
//
// Verify that the socket is connected
@@ -2092,8 +804,6 @@ EslUdpTxBuffer4 (
// Determine the queue head
//
pUdp4 = &pPort->Context.Udp4;
- ppPacket = &pUdp4->pTxPacket;
- pToken = &pUdp4->TxToken;
pTxBytes = &pSocket->TxBytes;
//
@@ -2108,6 +818,7 @@ EslUdpTxBuffer4 (
sizeof ( pPacket->Op.Udp4Tx )
- sizeof ( pPacket->Op.Udp4Tx.Buffer )
+ BufferLength,
+ 0,
DEBUG_TX );
if ( !EFI_ERROR ( Status )) {
//
@@ -2120,16 +831,18 @@ EslUdpTxBuffer4 (
pTxData->TxData.FragmentCount = 1;
pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;
pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Udp4Tx.Buffer[0];
+ pTxData->RetransmitCount = 0;
//
// Set the remote system address if necessary
//
+ pTxData->TxData.UdpSessionData = NULL;
if ( NULL != pAddress ) {
pRemoteAddress = (const struct sockaddr_in *)pAddress;
- pTxData->Session.SourceAddress.Addr[0] = 0;
- pTxData->Session.SourceAddress.Addr[1] = 0;
- pTxData->Session.SourceAddress.Addr[2] = 0;
- pTxData->Session.SourceAddress.Addr[3] = 0;
+ pTxData->Session.SourceAddress.Addr[0] = pUdp4->ConfigData.StationAddress.Addr[0];
+ pTxData->Session.SourceAddress.Addr[1] = pUdp4->ConfigData.StationAddress.Addr[1];
+ pTxData->Session.SourceAddress.Addr[2] = pUdp4->ConfigData.StationAddress.Addr[2];
+ pTxData->Session.SourceAddress.Addr[3] = pUdp4->ConfigData.StationAddress.Addr[3];
pTxData->Session.SourcePort = 0;
pTxData->Session.DestinationAddress.Addr[0] = (UINT8)pRemoteAddress->sin_addr.s_addr;
pTxData->Session.DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
@@ -2192,8 +905,12 @@ EslUdpTxBuffer4 (
//
// Start the transmit engine if it is idle
//
- if ( NULL == pUdp4->pTxPacket ) {
- EslUdpTxStart4 ( pSocket->pPortList );
+ if ( NULL != pPort->pTxFree ) {
+ EslSocketTxStart ( pPort,
+ &pSocket->pTxPacketListHead,
+ &pSocket->pTxPacketListTail,
+ &pPort->pTxActive,
+ &pPort->pTxFree );
}
}
else {
@@ -2243,23 +960,27 @@ EslUdpTxBuffer4 (
/**
Process the transmit completion
- @param Event The normal transmit completion event
+ This routine use ::EslSocketTxComplete to perform the transmit
+ completion processing for data packets.
- @param pPort The DT_PORT structure address
+ This routine is called by the UDPv4 network layer when a data
+ transmit request completes.
+
+ @param [in] Event The normal transmit completion event
+
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
**/
VOID
-EslUdpTxComplete4 (
+EslUdp4TxComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_IO_MGMT * pIo
)
{
UINT32 LengthInBytes;
- DT_PACKET * pCurrentPacket;
- DT_PACKET * pNextPacket;
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_UDP4_CONTEXT * pUdp4;
+ ESL_PORT * pPort;
+ ESL_PACKET * pPacket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -2267,142 +988,69 @@ EslUdpTxComplete4 (
//
// Locate the active transmit packet
//
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
pSocket = pPort->pSocket;
- pUdp4 = &pPort->Context.Udp4;
- pPacket = pUdp4->pTxPacket;
-
+
//
- // Mark this packet as complete
+ // Get the transmit length and status
//
- pUdp4->pTxPacket = NULL;
LengthInBytes = pPacket->Op.Udp4Tx.TxData.DataLength;
pSocket->TxBytes -= LengthInBytes;
-
- //
- // Save any transmit error
- //
- Status = pUdp4->TxToken.Status;
- if ( EFI_ERROR ( Status )) {
- if ( !EFI_ERROR ( pSocket->TxError )) {
- pSocket->TxError = Status;
- }
- DEBUG (( DEBUG_TX | DEBUG_INFO,
- "ERROR - Transmit failure for packet 0x%08x, Status: %r\r\n",
- pPacket,
- Status ));
-
- //
- // Empty the normal transmit list
- //
- pCurrentPacket = pPacket;
- pNextPacket = pSocket->pTxPacketListHead;
- while ( NULL != pNextPacket ) {
- pPacket = pNextPacket;
- pNextPacket = pPacket->pNext;
- EslSocketPacketFree ( pPacket, DEBUG_TX );
- }
- pSocket->pTxPacketListHead = NULL;
- pSocket->pTxPacketListTail = NULL;
- pPacket = pCurrentPacket;
- }
- else
- {
- DEBUG (( DEBUG_TX | DEBUG_INFO,
- "0x%08x: Packet transmitted %d bytes successfully\r\n",
- pPacket,
- LengthInBytes ));
-
- //
- // Verify the transmit engine is still running
- //
- if ( !pPort->bCloseNow ) {
- //
- // Start the next packet transmission
- //
- EslUdpTxStart4 ( pPort );
- }
- }
-
- //
- // Release this packet
- //
- EslSocketPacketFree ( pPacket, DEBUG_TX );
-
+ Status = pIo->Token.Udp4Tx.Status;
+
//
- // Finish the close operation if necessary
+ // Complete the transmit operation
//
- if (( PORT_STATE_CLOSE_STARTED <= pPort->State )
- && ( NULL == pSocket->pTxPacketListHead )
- && ( NULL == pUdp4->pTxPacket )) {
- //
- // Indicate that the transmit is complete
- //
- EslUdpPortCloseTxDone4 ( pPort );
- }
+ EslSocketTxComplete ( pIo,
+ LengthInBytes,
+ Status,
+ "UDP ",
+ &pSocket->pTxPacketListHead,
+ &pSocket->pTxPacketListTail,
+ &pPort->pTxActive,
+ &pPort->pTxFree );
DBG_EXIT ( );
}
/**
- Transmit data using a network connection.
-
- @param [in] pPort Address of a DT_PORT structure
-
- **/
-VOID
-EslUdpTxStart4 (
- IN DT_PORT * pPort
- )
-{
- DT_PACKET * pNextPacket;
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_UDP4_PROTOCOL * pUdp4Protocol;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Assume success
- //
- Status = EFI_SUCCESS;
-
- //
- // Get the packet from the queue head
- //
- pSocket = pPort->pSocket;
- pPacket = pSocket->pTxPacketListHead;
- if ( NULL != pPacket ) {
- //
- // Remove the packet from the queue
- //
- pNextPacket = pPacket->pNext;
- pSocket->pTxPacketListHead = pNextPacket;
- if ( NULL == pNextPacket ) {
- pSocket->pTxPacketListTail = NULL;
- }
-
- //
- // Set the packet as active
- //
- pUdp4 = &pPort->Context.Udp4;
- pUdp4->pTxPacket = pPacket;
-
- //
- // Start the transmit operation
- //
- pUdp4Protocol = pUdp4->pProtocol;
- pUdp4->TxToken.Packet.TxData = &pPacket->Op.Udp4Tx.TxData;
- Status = pUdp4Protocol->Transmit ( pUdp4Protocol, &pUdp4->TxToken );
- if ( EFI_ERROR ( Status )) {
- pSocket = pPort->pSocket;
- if ( EFI_SUCCESS == pSocket->TxError ) {
- pSocket->TxError = Status;
- }
- }
- }
-
- DBG_EXIT ( );
-}
-
+ Interface between the socket layer and the network specific
+ code that supports SOCK_DGRAM sockets over UDPv4.
+**/
+CONST ESL_PROTOCOL_API cEslUdp4Api = {
+ "UDPv4",
+ IPPROTO_UDP,
+ OFFSET_OF ( ESL_PORT, Context.Udp4.ConfigData ),
+ OFFSET_OF ( ESL_LAYER, pUdp4List ),
+ OFFSET_OF ( struct sockaddr_in, sin_zero ),
+ sizeof ( struct sockaddr_in ),
+ AF_INET,
+ sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),
+ sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),
+ OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Rx.Packet.RxData ),
+ FALSE,
+ EADDRINUSE,
+ NULL, // Accept
+ NULL, // ConnectPoll
+ NULL, // ConnectStart
+ EslUdp4SocketIsConfigured,
+ EslUdp4LocalAddressGet,
+ EslUdp4LocalAddressSet,
+ NULL, // Listen
+ NULL, // OptionGet
+ NULL, // OptionSet
+ EslUdp4PacketFree,
+ EslUdp4PortAllocate,
+ NULL, // PortClose,
+ NULL, // PortCloseOp
+ TRUE,
+ EslUdp4Receive,
+ EslUdp4RemoteAddressGet,
+ EslUdp4RemoteAddressSet,
+ EslUdp4RxComplete,
+ NULL, // RxStart
+ EslUdp4TxBuffer,
+ EslUdp4TxComplete,
+ NULL // TxOobComplete
+};
diff --git a/StdLib/EfiSocketLib/UseEfiSocketLib.c b/StdLib/EfiSocketLib/UseEfiSocketLib.c
index a07b2b6e22..1c122af650 100644
--- a/StdLib/EfiSocketLib/UseEfiSocketLib.c
+++ b/StdLib/EfiSocketLib/UseEfiSocketLib.c
@@ -15,14 +15,30 @@
#include "Socket.h"
-CONST EFI_GUID mEslRawServiceGuid = {
- 0xc31bf4a5, 0x2c7, 0x49d2, { 0xa5, 0x58, 0xfe, 0x62, 0x6f, 0x7e, 0xd4, 0x77 }
+/**
+ The following GUID values are only used when an application links
+ against EfiSocketLib. An alternative set of values exists in
+ SocketDxe\EntryUnload.c which the SocketDxe driver uses to coexist
+ with socket applications.
+
+ Tag GUID - IPv4 in use by an application using EfiSocketLib
+**/
+CONST EFI_GUID mEslIp4ServiceGuid = {
+ 0x9c756011, 0x5d44, 0x4ee0, { 0xbc, 0xe7, 0xc3, 0x82, 0x18, 0xfe, 0x39, 0x8d }
};
+
+/**
+ Tag GUID - TCPv4 in use by an application using EfiSocketLib
+**/
CONST EFI_GUID mEslTcp4ServiceGuid = {
0xffc659c2, 0x4ef2, 0x4532, { 0xb8, 0x75, 0xcd, 0x9a, 0xa4, 0x27, 0x4c, 0xde }
};
+
+/**
+ Tag GUID - UDPv4 in use by an application using EfiSocketLib
+**/
CONST EFI_GUID mEslUdp4ServiceGuid = {
0x44e03a55, 0x8d97, 0x4511, { 0xbf, 0xef, 0xa, 0x8b, 0xc6, 0x2c, 0x25, 0xae }
};
@@ -31,10 +47,20 @@ CONST EFI_GUID mEslUdp4ServiceGuid = {
/**
Connect to the EFI socket library
- @param [in] ppSocketProtocol Address to receive the socket protocol address
+ This routine creates the ::ESL_SOCKET structure and returns
+ the API (::EFI_SOCKET_PROTOCOL address) to the socket file
+ system layer in BsdSocketLib.
+
+ This routine is called from the ::socket routine in BsdSocketLib
+ to create the data structure and initialize the API for a socket.
+ Note that this implementation is only used by socket applications
+ that link directly to EslSocketLib.
+
+ @param [in] ppSocketProtocol Address to receive the ::EFI_SOCKET_PROTOCOL
+ structure address
+
+ @return Value for ::errno, zero (0) indicates success.
- @retval 0 Successfully returned the socket protocol
- @retval other Value for errno
**/
int
EslServiceGetProtocol (
@@ -42,7 +68,7 @@ EslServiceGetProtocol (
)
{
EFI_HANDLE ChildHandle;
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pSocket;
int RetVal;
EFI_STATUS Status;
@@ -81,6 +107,16 @@ EslServiceGetProtocol (
/**
Connect to the network layer
+ This routine is the constructor for the EfiSocketLib when the
+ library is linked directly to an application. This routine
+ walks the ::cEslSocketBinding table to create ::ESL_SERVICE
+ structures, associated with the network adapters, which this
+ routine links to the ::ESL_LAYER structure.
+
+ This routine is called from ::EslConstructor as a result of the
+ constructor redirection in ::mpfnEslConstructor at the end of this
+ file.
+
@retval EFI_SUCCESS Successfully connected to the network layer
**/
@@ -89,11 +125,12 @@ EslServiceNetworkConnect (
VOID
)
{
+ BOOLEAN bSomethingFound;
UINTN HandleCount;
- EFI_HANDLE * pHandles;
UINTN Index;
- CONST DT_SOCKET_BINDING * pSocketBinding;
- CONST DT_SOCKET_BINDING * pEnd;
+ CONST ESL_SOCKET_BINDING * pEnd;
+ EFI_HANDLE * pHandles;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -102,13 +139,14 @@ EslServiceNetworkConnect (
// Initialize the socket layer
//
Status = EFI_SUCCESS;
+ bSomethingFound = FALSE;
EslServiceLoad ( gImageHandle );
//
// Connect the network devices
//
- pSocketBinding = &cEslSocketBinding [0];
- pEnd = &pSocketBinding [ cEslSocketBindingEntries ];
+ pSocketBinding = &cEslSocketBinding[0];
+ pEnd = &pSocketBinding[ cEslSocketBindingEntries ];
while ( pEnd > pSocketBinding ) {
//
// Attempt to locate the network adapters
@@ -121,24 +159,30 @@ EslServiceNetworkConnect (
&HandleCount,
&pHandles );
if ( EFI_ERROR ( Status )) {
- break;
+ DEBUG (( DEBUG_ERROR,
+ "ERROR with %s layer, Status: %r\r\n",
+ pSocketBinding->pName,
+ Status ));
}
- if ( NULL != pHandles ) {
- //
- // Attempt to connect to this network adapter
- //
- for ( Index = 0; HandleCount > Index; Index++ ) {
- Status = EslServiceConnect ( gImageHandle,
- pHandles [ Index ]);
- if ( EFI_ERROR ( Status )) {
- break;
+ else {
+ if ( NULL != pHandles ) {
+ //
+ // Attempt to connect to this network adapter
+ //
+ for ( Index = 0; HandleCount > Index; Index++ ) {
+ Status = EslServiceConnect ( gImageHandle,
+ pHandles[ Index ]);
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+ bSomethingFound = TRUE;
}
- }
- //
- // Done with the handles
- //
- gBS->FreePool ( pHandles );
+ //
+ // Done with the handles
+ //
+ gBS->FreePool ( pHandles );
+ }
}
//
@@ -150,6 +194,9 @@ EslServiceNetworkConnect (
//
// Return the network connection status
//
+ if ( bSomethingFound ) {
+ Status = EFI_SUCCESS;
+ }
DBG_EXIT_STATUS ( Status );
return Status;
}
@@ -158,6 +205,15 @@ EslServiceNetworkConnect (
/**
Disconnect from the network layer
+ Destructor for the EfiSocketLib when the library is linked
+ directly to an application. This routine walks the
+ ::cEslSocketBinding table to remove the ::ESL_SERVICE
+ structures (network connections) from the ::ESL_LAYER structure.
+
+ This routine is called from ::EslDestructor as a result of the
+ destructor redirection in ::mpfnEslDestructor at the end of this
+ file.
+
@retval EFI_SUCCESS Successfully disconnected from the network layer
**/
@@ -167,10 +223,10 @@ EslServiceNetworkDisconnect (
)
{
UINTN HandleCount;
- EFI_HANDLE * pHandles;
UINTN Index;
- CONST DT_SOCKET_BINDING * pSocketBinding;
- CONST DT_SOCKET_BINDING * pEnd;
+ CONST ESL_SOCKET_BINDING * pEnd;
+ EFI_HANDLE * pHandles;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -183,8 +239,8 @@ EslServiceNetworkDisconnect (
//
// Disconnect the network devices
//
- pSocketBinding = &cEslSocketBinding [0];
- pEnd = &pSocketBinding [ cEslSocketBindingEntries ];
+ pSocketBinding = &cEslSocketBinding[0];
+ pEnd = &pSocketBinding[ cEslSocketBindingEntries ];
while ( pEnd > pSocketBinding ) {
//
// Attempt to locate the network adapters
@@ -205,7 +261,7 @@ EslServiceNetworkDisconnect (
//
for ( Index = 0; HandleCount > Index; Index++ ) {
Status = EslServiceDisconnect ( gImageHandle,
- pHandles [ Index ]);
+ pHandles[ Index ]);
if ( EFI_ERROR ( Status )) {
break;
}
@@ -238,5 +294,19 @@ EslServiceNetworkDisconnect (
}
-PFN_ESL_xSTRUCTOR mpfnEslConstructor = EslServiceNetworkConnect;
-PFN_ESL_xSTRUCTOR mpfnEslDestructor = EslServiceNetworkDisconnect;
+/**
+ Socket layer's service binding protocol delcaration.
+**/
+CONST EFI_SERVICE_BINDING_PROTOCOL mEfiServiceBinding = {
+ NULL,
+ NULL
+};
+
+
+/**
+ The following entries redirect the constructor and destructor
+ for any socket application that links against the EfiSocketLib.
+ Note that the SocketDxe driver uses different redirection.
+**/
+PFN_ESL_xSTRUCTOR mpfnEslConstructor = EslServiceNetworkConnect; ///< Constructor for EfiSocketLib
+PFN_ESL_xSTRUCTOR mpfnEslDestructor = EslServiceNetworkDisconnect; ///< Destructor for EfiSocketLib