mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 20:43:59 +00:00 
			
		
		
		
	 a88c31639b
			
		
	
	
		a88c31639b
		
	
	
	
	
		
			
			* 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
		
			
				
	
	
		
			495 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			495 lines
		
	
	
		
			15 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 other                This driver does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EslServiceConnect (
 | |
|   IN EFI_HANDLE BindingHandle,
 | |
|   IN EFI_HANDLE Controller
 | |
|   )
 | |
| {
 | |
|   BOOLEAN bInUse;
 | |
|   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
 | |
|   //
 | |
|   Status = 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 );
 | |
| 
 | |
|               //
 | |
|               //  Determine if the initialization was successful
 | |
|               //
 | |
|               if ( EFI_ERROR ( Status )) {
 | |
|                 DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
 | |
|                           "ERROR - Failed to initialize service %s on 0x%08x, Status: %r\r\n",
 | |
|                           pSocketBinding->pName,
 | |
|                           Controller,
 | |
|                           Status ));
 | |
| 
 | |
|                 //
 | |
|                 //  Free the network service binding if necessary
 | |
|                 //
 | |
|                 gBS->UninstallMultipleProtocolInterfaces (
 | |
|                           Controller,
 | |
|                           pSocketBinding->pTagGuid,
 | |
|                           pService,
 | |
|                           NULL );
 | |
|                 DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
 | |
|                             "Removed:   %s TagGuid from 0x%08x\r\n",
 | |
|                             pSocketBinding->pName,
 | |
|                             Controller ));
 | |
|               }
 | |
|             }
 | |
|             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 ));
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   
 | |
|     //
 | |
|     //  Set the next network protocol
 | |
|     //
 | |
|     pSocketBinding += 1;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   //  Display the driver start status
 | |
|   //
 | |
|   DBG_EXIT_STATUS ( Status );
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   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;
 | |
| }
 |