Service.c - Return EFI_SUCCESS if any of the protocols are present. Return failure only when no protocols are available or no more memory available. Signed-off-by: lpleahy Reviewed-by: vzimmer git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13426 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			480 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			480 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Connect to and disconnect from the various network layers
 | 
						|
 | 
						|
  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"
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  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;
 | 
						|
}
 |