From 4652be0c5a106d0604c2d3274803fc0f844b0433 Mon Sep 17 00:00:00 2001 From: lpleahy Date: Mon, 8 Oct 2012 21:39:35 +0000 Subject: [PATCH] Fixed close for socket to properly release the socket context structure and the handle. Signed-off-by: lpleahy git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13802 6f19259b-4bc3-4df7-8a09-765794883524 --- StdLib/BsdSocketLib/close.c | 17 +-- StdLib/EfiSocketLib/DxeSupport.c | 98 +--------------- StdLib/EfiSocketLib/Socket.c | 162 ++++++++++++++++++++++++++ StdLib/EfiSocketLib/Socket.h | 22 ++++ StdLib/EfiSocketLib/UseEfiSocketLib.c | 34 ++++++ StdLib/Include/Protocol/EfiSocket.h | 20 ++++ StdLib/UseSocketDxe/UseSocketDxe.c | 53 +++++++++ 7 files changed, 295 insertions(+), 111 deletions(-) diff --git a/StdLib/BsdSocketLib/close.c b/StdLib/BsdSocketLib/close.c index f3f7e98cba..01eb48ecb5 100644 --- a/StdLib/BsdSocketLib/close.c +++ b/StdLib/BsdSocketLib/close.c @@ -31,7 +31,6 @@ BslSocketCloseWork ( IN int * pErrno ) { - EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding; EFI_STATUS Status; // @@ -50,21 +49,9 @@ BslSocketCloseWork ( } if ( !EFI_ERROR ( Status )) { // - // Locate the socket protocol + // Release the socket resources // - Status = gBS->LocateProtocol ( &gEfiSocketServiceBindingProtocolGuid, - NULL, - (VOID **) &pServiceBinding ); - if ( !EFI_ERROR ( Status )) { - // - // Release the handle - // - Status = pServiceBinding->DestroyChild ( pServiceBinding, - pSocketProtocol->SocketHandle ); - } - if ( EFI_ERROR ( Status )) { - *pErrno = EIO; - } + *pErrno = EslServiceFreeProtocol ( pSocketProtocol ); } else { DEBUG (( DEBUG_ERROR, diff --git a/StdLib/EfiSocketLib/DxeSupport.c b/StdLib/EfiSocketLib/DxeSupport.c index 284fa9cdfe..808b710d27 100644 --- a/StdLib/EfiSocketLib/DxeSupport.c +++ b/StdLib/EfiSocketLib/DxeSupport.c @@ -91,11 +91,8 @@ EslDxeDestroyChild ( ) { ESL_LAYER * pLayer; - ESL_SOCKET * pSocket; - ESL_SOCKET * pSocketPrevious; EFI_SOCKET_PROTOCOL * pSocketProtocol; EFI_STATUS Status; - EFI_TPL TplPrevious; DBG_ENTER ( ); @@ -112,101 +109,10 @@ EslDxeDestroyChild ( 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 + // Free the socket resources // - 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; - } + Status = EslSocketFree ( pSocketProtocol, NULL ); } else { DEBUG (( DEBUG_ERROR, diff --git a/StdLib/EfiSocketLib/Socket.c b/StdLib/EfiSocketLib/Socket.c index e718e9bdf8..52e5f2948e 100644 --- a/StdLib/EfiSocketLib/Socket.c +++ b/StdLib/EfiSocketLib/Socket.c @@ -1945,6 +1945,168 @@ EslSocketCopyFragmentedBuffer ( } +/** + Free the socket. + + This routine frees the socket structure and handle resources. + + The ::close routine calls EslServiceFreeProtocol which then calls + this routine to free the socket context structure and close the + handle. + + @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure. + + @param [out] pErrno Address to receive the errno value upon completion. + + @retval EFI_SUCCESS The socket resources were returned successfully. + + **/ +EFI_STATUS +EslSocketFree ( + IN EFI_SOCKET_PROTOCOL * pSocketProtocol, + IN int * pErrno + ) +{ + EFI_HANDLE ChildHandle; + int errno; + ESL_LAYER * pLayer; + ESL_SOCKET * pSocket; + ESL_SOCKET * pSocketPrevious; + EFI_STATUS Status; + EFI_TPL TplPrevious; + + DBG_ENTER ( ); + + // + // Assume failure + // + errno = EIO; + pSocket = NULL; + Status = EFI_INVALID_PARAMETER; + + // + // Validate the socket + // + pLayer = &mEslLayer; + if ( NULL != pSocketProtocol ) { + 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 + // + ChildHandle = pSocket->SocketProtocol.SocketHandle; + 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 ))); + errno = 0; + } + 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 - Invalid parameter pSocketProtocol is NULL\r\n" )); + } + + // + // Return the errno value if possible + // + if ( NULL != pErrno ) { + *pErrno = errno; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + /** Get the local address. diff --git a/StdLib/EfiSocketLib/Socket.h b/StdLib/EfiSocketLib/Socket.h index f2fbdb57b3..43a7084f95 100644 --- a/StdLib/EfiSocketLib/Socket.h +++ b/StdLib/EfiSocketLib/Socket.h @@ -1187,6 +1187,28 @@ EslSocketCopyFragmentedBuffer ( OUT size_t * pDataLength ); +/** + Free the socket. + + This routine frees the socket structure and handle resources. + + The ::close routine calls EslServiceFreeProtocol which then calls + this routine to free the socket context structure and close the + handle. + + @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure. + + @param [out] pErrno Address to receive the errno value upon completion. + + @retval EFI_SUCCESS The socket resources were returned successfully. + + **/ +EFI_STATUS +EslSocketFree ( + IN EFI_SOCKET_PROTOCOL * pSocketProtocol, + IN int * pErrno + ); + /** Free the ESL_IO_MGMT event and structure diff --git a/StdLib/EfiSocketLib/UseEfiSocketLib.c b/StdLib/EfiSocketLib/UseEfiSocketLib.c index e44a720435..060598af31 100644 --- a/StdLib/EfiSocketLib/UseEfiSocketLib.c +++ b/StdLib/EfiSocketLib/UseEfiSocketLib.c @@ -68,6 +68,40 @@ CONST EFI_GUID mEslUdp6ServiceGuid __attribute__((weak)) = { }; +/** + Free the socket resources + + This releases the socket resources allocated by calling + EslServiceGetProtocol. + + This routine is called from the ::close routine in BsdSocketLib + to release the socket resources. + + @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL + structure + + @return Value for ::errno, zero (0) indicates success. + + **/ +int +EslServiceFreeProtocol ( + IN EFI_SOCKET_PROTOCOL * pSocketProtocol + ) +{ + int RetVal; + + // + // Release the socket resources + // + EslSocketFree ( pSocketProtocol, &RetVal ); + + // + // Return the operation status + // + return RetVal; +} + + /** Connect to the EFI socket library diff --git a/StdLib/Include/Protocol/EfiSocket.h b/StdLib/Include/Protocol/EfiSocket.h index 2664f01bdb..022a6a5f22 100644 --- a/StdLib/Include/Protocol/EfiSocket.h +++ b/StdLib/Include/Protocol/EfiSocket.h @@ -612,6 +612,26 @@ AcceptNB ( socklen_t * address_len ); +/** + Free the socket resources + + This releases the socket resources allocated by calling + EslServiceGetProtocol. + + This routine is called from the ::close routine in BsdSocketLib + to release the socket resources. + + @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL + structure + + @return Value for ::errno, zero (0) indicates success. + + **/ +int +EslServiceFreeProtocol ( + IN EFI_SOCKET_PROTOCOL * pSocketProtocol + ); + /** Connect to the EFI socket library diff --git a/StdLib/UseSocketDxe/UseSocketDxe.c b/StdLib/UseSocketDxe/UseSocketDxe.c index 6074143264..423419c23e 100644 --- a/StdLib/UseSocketDxe/UseSocketDxe.c +++ b/StdLib/UseSocketDxe/UseSocketDxe.c @@ -22,6 +22,59 @@ #include +/** + Free the socket resources + + This releases the socket resources allocated by calling + EslServiceGetProtocol. + + This routine is called from the ::close routine in BsdSocketLib + to release the socket resources. + + @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL + structure + + @return Value for ::errno, zero (0) indicates success. + + **/ +int +EslServiceFreeProtocol ( + IN EFI_SOCKET_PROTOCOL * pSocketProtocol + ) +{ + EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding; + int RetVal; + EFI_STATUS Status; + + // + // Assume success + // + RetVal = 0; + + // + // Locate the socket protocol + // + Status = gBS->LocateProtocol ( &gEfiSocketServiceBindingProtocolGuid, + NULL, + (VOID **) &pServiceBinding ); + if ( !EFI_ERROR ( Status )) { + // + // Release the handle + // + Status = pServiceBinding->DestroyChild ( pServiceBinding, + pSocketProtocol->SocketHandle ); + } + if ( EFI_ERROR ( Status )) { + RetVal = EIO; + } + + // + // Return the operation status + // + return RetVal; +} + + /** Connect to the EFI socket library -- 2.39.2