audk/StdLib/EfiSocketLib/Service.c

474 lines
14 KiB
C

/** @file
Connect to and disconnect from the various network layers
Copyright (c) 2011, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Socket.h"
/**
Connect to the network service bindings
Walk the network service protocols on the controller handle and
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.
@retval EFI_SUCCESS This driver is added to Controller.
@retval EFI_OUT_OF_RESOURCES No more memory available.
@retval EFI_UNSUPPORTED This driver does not support this device.
**/
EFI_STATUS
EFIAPI
EslServiceConnect (
IN EFI_HANDLE BindingHandle,
IN EFI_HANDLE Controller
)
{
BOOLEAN bInUse;
EFI_STATUS ExitStatus;
UINTN LengthInBytes;
UINT8 * pBuffer;
CONST ESL_SOCKET_BINDING * pEnd;
VOID * pJunk;
ESL_SERVICE ** ppServiceListHead;
ESL_SERVICE * pService;
CONST ESL_SOCKET_BINDING * pSocketBinding;
EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
EFI_STATUS Status;
EFI_TPL TplPrevious;
DBG_ENTER ( );
//
// Assume the list is empty
//
ExitStatus = EFI_UNSUPPORTED;
bInUse = FALSE;
//
// Walk the list of network connection points
//
pSocketBinding = &cEslSocketBinding[0];
pEnd = &pSocketBinding[ cEslSocketBindingEntries ];
while ( pEnd > pSocketBinding ) {
//
// Determine if the controller supports the network protocol
//
Status = gBS->OpenProtocol (
Controller,
pSocketBinding->pNetworkBinding,
(VOID**)&pServiceBinding,
BindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if ( !EFI_ERROR ( Status )) {
//
// Determine if the socket layer is already connected
//
Status = gBS->OpenProtocol (
Controller,
(EFI_GUID *)pSocketBinding->pTagGuid,
&pJunk,
BindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if ( EFI_UNSUPPORTED == Status ) {
//
// Allocate a service structure since the tag is not present
//
LengthInBytes = sizeof ( *pService );
Status = gBS->AllocatePool (
EfiRuntimeServicesData,
LengthInBytes,
(VOID **) &pService
);
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_POOL | DEBUG_INIT,
"0x%08x: Allocate pService, %d bytes\r\n",
pService,
LengthInBytes ));
//
// Set the structure signature and service binding
//
ZeroMem ( pService, LengthInBytes );
pService->Signature = SERVICE_SIGNATURE;
pService->pSocketBinding = pSocketBinding;
pService->Controller = Controller;
pService->pServiceBinding = pServiceBinding;
//
// Mark the controller in use
//
if ( !bInUse ) {
Status = gBS->InstallMultipleProtocolInterfaces (
&Controller,
&gEfiCallerIdGuid,
NULL,
NULL
);
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
"Installed: gEfiCallerIdGuid on 0x%08x\r\n",
Controller ));
bInUse = TRUE;
}
else {
if ( EFI_INVALID_PARAMETER == Status ) {
Status = EFI_SUCCESS;
}
}
}
if ( !EFI_ERROR ( Status )) {
//
// Mark the network service protocol in use
//
Status = gBS->InstallMultipleProtocolInterfaces (
&Controller,
pSocketBinding->pTagGuid,
pService,
NULL
);
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
"Installed: %s TagGuid on 0x%08x\r\n",
pSocketBinding->pName,
Controller ));
//
// Synchronize with the socket layer
//
RAISE_TPL ( TplPrevious, TPL_SOCKETS );
//
// Connect the service to the list
//
pBuffer = (UINT8 *)&mEslLayer;
pBuffer = &pBuffer[ pSocketBinding->ServiceListOffset ];
ppServiceListHead = (ESL_SERVICE **)pBuffer;
pService->pNext = *ppServiceListHead;
*ppServiceListHead = pService;
//
// Release the socket layer synchronization
//
RESTORE_TPL ( TplPrevious );
//
// At least one service was made available
//
ExitStatus = EFI_SUCCESS;
}
else {
DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
"ERROR - Failed to install %s TagGuid on 0x%08x, Status: %r\r\n",
pSocketBinding->pName,
Controller,
Status ));
}
if ( EFI_ERROR ( Status )) {
//
// The controller is no longer in use
//
if ( bInUse ) {
gBS->UninstallMultipleProtocolInterfaces (
Controller,
&gEfiCallerIdGuid,
NULL,
NULL );
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
"Removed: gEfiCallerIdGuid from 0x%08x\r\n",
Controller ));
}
}
}
else {
DEBUG (( DEBUG_ERROR | DEBUG_INIT,
"ERROR - Failed to install gEfiCallerIdGuid on 0x%08x, Status: %r\r\n",
Controller,
Status ));
}
//
// Release the service if necessary
//
if ( EFI_ERROR ( Status )) {
gBS->FreePool ( pService );
DEBUG (( DEBUG_POOL | DEBUG_INIT,
"0x%08x: Free pService, %d bytes\r\n",
pService,
sizeof ( *pService )));
pService = NULL;
}
}
else {
DEBUG (( DEBUG_ERROR | DEBUG_INIT,
"ERROR - Failed service allocation, Status: %r\r\n",
Status ));
ExitStatus = EFI_OUT_OF_RESOURCES;
break;
}
}
}
//
// Set the next network protocol
//
pSocketBinding += 1;
}
//
// Display the driver start status
//
DBG_EXIT_STATUS ( ExitStatus );
return ExitStatus;
}
/**
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.
@retval EFI_SUCCESS This driver is removed Controller.
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
@retval other This driver was not removed from this device.
**/
EFI_STATUS
EFIAPI
EslServiceDisconnect (
IN EFI_HANDLE BindingHandle,
IN EFI_HANDLE Controller
)
{
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;
DBG_ENTER ( );
//
// Walk the list of network connection points in reverse order
//
pEnd = &cEslSocketBinding[0];
pSocketBinding = &pEnd[ cEslSocketBindingEntries ];
while ( pEnd < pSocketBinding ) {
//
// Set the next network protocol
//
pSocketBinding -= 1;
//
// Determine if the driver connected
//
Status = gBS->OpenProtocol (
Controller,
(EFI_GUID *)pSocketBinding->pTagGuid,
(VOID **)&pService,
BindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if ( !EFI_ERROR ( Status )) {
//
// Synchronize with the socket layer
//
RAISE_TPL ( TplPrevious, TPL_SOCKETS );
//
// Walk the list of ports
//
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
//
RESTORE_TPL ( TplPrevious );
//
// Break the driver connection
//
Status = gBS->UninstallMultipleProtocolInterfaces (
Controller,
pSocketBinding->pTagGuid,
pService,
NULL );
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_POOL | DEBUG_INIT,
"Removed: %s TagGuid from 0x%08x\r\n",
pSocketBinding->pName,
Controller ));
}
else {
DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
"ERROR - Failed to removed %s TagGuid from 0x%08x, Status: %r\r\n",
pSocketBinding->pName,
Controller,
Status ));
}
//
// Free the service structure
//
Status = gBS->FreePool ( pService );
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_POOL | DEBUG_INIT,
"0x%08x: Free pService, %d bytes\r\n",
pService,
sizeof ( *pService )));
}
else {
DEBUG (( DEBUG_POOL | DEBUG_INIT,
"ERROR - Failed to free pService 0x%08x, Status: %r\r\n",
pService,
Status ));
}
pService = NULL;
}
}
//
// The controller is no longer in use
//
gBS->UninstallMultipleProtocolInterfaces (
Controller,
&gEfiCallerIdGuid,
NULL,
NULL );
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
"Removed: gEfiCallerIdGuid from 0x%08x\r\n",
Controller ));
//
// The driver is disconnected from the network controller
//
Status = EFI_SUCCESS;
//
// Display the driver start status
//
DBG_EXIT_STATUS ( Status );
return Status;
}
/**
Initialize the service layer
@param [in] ImageHandle Handle for the image.
**/
VOID
EFIAPI
EslServiceLoad (
IN EFI_HANDLE ImageHandle
)
{
ESL_LAYER * pLayer;
//
// Save the image handle
//
pLayer = &mEslLayer;
ZeroMem ( pLayer, sizeof ( *pLayer ));
pLayer->Signature = LAYER_SIGNATURE;
pLayer->ImageHandle = ImageHandle;
//
// Connect the service binding protocol to the image handle
//
pLayer->pServiceBinding = &mEfiServiceBinding;
}
/**
Shutdown the service layer
**/
VOID
EFIAPI
EslServiceUnload (
VOID
)
{
ESL_LAYER * pLayer;
//
// Undo the work by ServiceLoad
//
pLayer = &mEslLayer;
pLayer->ImageHandle = NULL;
pLayer->pServiceBinding = NULL;
}