git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@7290 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			982 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			982 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  The driver binding and service binding protocol for IP4 driver.
 | 
						|
  
 | 
						|
Copyright (c) 2005 - 2006, Intel Corporation.<BR>
 | 
						|
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 "Ip4Impl.h"
 | 
						|
 | 
						|
EFI_DRIVER_BINDING_PROTOCOL gIp4DriverBinding = {
 | 
						|
  Ip4DriverBindingSupported,
 | 
						|
  Ip4DriverBindingStart,
 | 
						|
  Ip4DriverBindingStop,
 | 
						|
  0xa,
 | 
						|
  NULL,
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  This is the declaration of an EFI image entry point. This entry point is
 | 
						|
  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
 | 
						|
  both device drivers and bus drivers.
 | 
						|
  
 | 
						|
  The entry point for IP4 driver which install the driver
 | 
						|
  binding and component name protocol on its image.
 | 
						|
 | 
						|
  @param[in]  ImageHandle           The firmware allocated handle for the UEFI image.
 | 
						|
  @param[in]  SystemTable           A pointer to the EFI System Table.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The operation completed successfully.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
Ip4DriverEntryPoint (
 | 
						|
  IN EFI_HANDLE             ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE       *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  return EfiLibInstallDriverBindingComponentName2 (
 | 
						|
           ImageHandle,
 | 
						|
           SystemTable,
 | 
						|
           &gIp4DriverBinding,
 | 
						|
           ImageHandle,
 | 
						|
           &gIp4ComponentName,
 | 
						|
           &gIp4ComponentName2
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Test to see if this driver supports ControllerHandle. This service
 | 
						|
  is called by the EFI boot service ConnectController(). In
 | 
						|
  order to make drivers as small as possible, there are a few calling
 | 
						|
  restrictions for this service. ConnectController() must
 | 
						|
  follow these calling restrictions. If any other agent wishes to call
 | 
						|
  Supported() it must also follow these calling restrictions.
 | 
						|
 | 
						|
  @param[in]  This                Protocol instance pointer.
 | 
						|
  @param[in]  ControllerHandle    Handle of device to test
 | 
						|
  @param[in]  RemainingDevicePath Optional parameter use to pick a specific child
 | 
						|
                                  device to start.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS         This driver supports this device
 | 
						|
  @retval EFI_ALREADY_STARTED This driver is already running on this device
 | 
						|
  @retval other               This driver does not support this device
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
Ip4DriverBindingSupported (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL  * This,
 | 
						|
  IN EFI_HANDLE                   ControllerHandle,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Test for the MNP service binding Protocol
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  ControllerHandle,
 | 
						|
                  &gEfiManagedNetworkServiceBindingProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  ControllerHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Test for the Arp service binding Protocol
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  ControllerHandle,
 | 
						|
                  &gEfiArpServiceBindingProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  ControllerHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | 
						|
                  );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Clean up a IP4 service binding instance. It will release all
 | 
						|
  the resource allocated by the instance. The instance may be
 | 
						|
  partly initialized, or partly destroyed. If a resource is
 | 
						|
  destroyed, it is marked as that in case the destory failed and
 | 
						|
  being called again later.
 | 
						|
 | 
						|
  @param[in]  IpSb               The IP4 serviceing binding instance to clean up
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The resource used by the instance are cleaned up
 | 
						|
  @retval other                  Failed to clean up some of the resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ip4CleanService (
 | 
						|
  IN IP4_SERVICE            *IpSb
 | 
						|
  );
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Create a new IP4 driver service binding private instance.
 | 
						|
 | 
						|
  @param  Controller         The controller that has MNP service binding
 | 
						|
                             installed
 | 
						|
  @param  ImageHandle        The IP4 driver's image handle
 | 
						|
  @param  Service            The variable to receive the newly created IP4
 | 
						|
                             service.
 | 
						|
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resource
 | 
						|
  @retval EFI_SUCCESS            A new IP4 service binding private is created.
 | 
						|
  @retval other                  Other error occurs.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ip4CreateService (
 | 
						|
  IN  EFI_HANDLE            Controller,
 | 
						|
  IN  EFI_HANDLE            ImageHandle,
 | 
						|
  OUT IP4_SERVICE           **Service
 | 
						|
  )
 | 
						|
{
 | 
						|
  IP4_SERVICE               *IpSb;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  ASSERT (Service != NULL);
 | 
						|
 | 
						|
  *Service = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // allocate a service private data then initialize all the filed to
 | 
						|
  // empty resources, so if any thing goes wrong when allocating
 | 
						|
  // resources, Ip4CleanService can be called to clean it up.
 | 
						|
  //
 | 
						|
  IpSb = AllocatePool (sizeof (IP4_SERVICE));
 | 
						|
 | 
						|
  if (IpSb == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  IpSb->Signature                   = IP4_SERVICE_SIGNATURE;
 | 
						|
  IpSb->ServiceBinding.CreateChild  = Ip4ServiceBindingCreateChild;
 | 
						|
  IpSb->ServiceBinding.DestroyChild = Ip4ServiceBindingDestroyChild;
 | 
						|
  IpSb->State                       = IP4_SERVICE_UNSTARTED;
 | 
						|
  IpSb->InDestory                   = FALSE;
 | 
						|
 | 
						|
  IpSb->NumChildren                 = 0;
 | 
						|
  InitializeListHead (&IpSb->Children);
 | 
						|
 | 
						|
  InitializeListHead (&IpSb->Interfaces);
 | 
						|
  IpSb->DefaultInterface            = NULL;
 | 
						|
  IpSb->DefaultRouteTable           = NULL;
 | 
						|
 | 
						|
  Ip4InitAssembleTable (&IpSb->Assemble);
 | 
						|
 | 
						|
  IpSb->IgmpCtrl.Igmpv1QuerySeen    = 0;
 | 
						|
  InitializeListHead (&IpSb->IgmpCtrl.Groups);
 | 
						|
 | 
						|
  IpSb->Image                       = ImageHandle;
 | 
						|
  IpSb->Controller                  = Controller;
 | 
						|
 | 
						|
  IpSb->MnpChildHandle              = NULL;
 | 
						|
  IpSb->Mnp                         = NULL;
 | 
						|
 | 
						|
  IpSb->MnpConfigData.ReceivedQueueTimeoutValue = 0;
 | 
						|
  IpSb->MnpConfigData.TransmitQueueTimeoutValue = 0;
 | 
						|
  IpSb->MnpConfigData.ProtocolTypeFilter        = IP4_ETHER_PROTO;
 | 
						|
  IpSb->MnpConfigData.EnableUnicastReceive      = TRUE;
 | 
						|
  IpSb->MnpConfigData.EnableMulticastReceive    = TRUE;
 | 
						|
  IpSb->MnpConfigData.EnableBroadcastReceive    = TRUE;
 | 
						|
  IpSb->MnpConfigData.EnablePromiscuousReceive  = FALSE;
 | 
						|
  IpSb->MnpConfigData.FlushQueuesOnReset        = TRUE;
 | 
						|
  IpSb->MnpConfigData.EnableReceiveTimestamps   = FALSE;
 | 
						|
  IpSb->MnpConfigData.DisableBackgroundPolling  = FALSE;
 | 
						|
 | 
						|
  ZeroMem (&IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));
 | 
						|
 | 
						|
  IpSb->Timer                       = NULL;
 | 
						|
  IpSb->Ip4Config                   = NULL;
 | 
						|
  IpSb->DoneEvent                   = NULL;
 | 
						|
  IpSb->ReconfigEvent               = NULL;
 | 
						|
  IpSb->ActiveEvent                 = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create various resources. First create the route table, timer
 | 
						|
  // event and MNP child. IGMP, interface's initialization depend
 | 
						|
  // on the MNP child.
 | 
						|
  //
 | 
						|
  IpSb->DefaultRouteTable = Ip4CreateRouteTable ();
 | 
						|
 | 
						|
  if (IpSb->DefaultRouteTable == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_NOTIFY_SIGNAL | EVT_TIMER,
 | 
						|
                  TPL_CALLBACK,
 | 
						|
                  Ip4TimerTicking,
 | 
						|
                  IpSb,
 | 
						|
                  &IpSb->Timer
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = NetLibCreateServiceChild (
 | 
						|
             Controller,
 | 
						|
             ImageHandle,
 | 
						|
             &gEfiManagedNetworkServiceBindingProtocolGuid,
 | 
						|
             &IpSb->MnpChildHandle
 | 
						|
             );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  IpSb->MnpChildHandle,
 | 
						|
                  &gEfiManagedNetworkProtocolGuid,
 | 
						|
                  (VOID **) &IpSb->Mnp,
 | 
						|
                  ImageHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Ip4ServiceConfigMnp (IpSb, TRUE);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Ip4InitIgmp (IpSb);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  IpSb->DefaultInterface = Ip4CreateInterface (IpSb->Mnp, Controller, ImageHandle);
 | 
						|
 | 
						|
  if (IpSb->DefaultInterface == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  InsertHeadList (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);
 | 
						|
 | 
						|
  IpSb->MacString = NULL;
 | 
						|
 | 
						|
  *Service = IpSb;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
  Ip4CleanService (IpSb);
 | 
						|
  gBS->FreePool (IpSb);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Clean up a IP4 service binding instance. It will release all
 | 
						|
  the resource allocated by the instance. The instance may be
 | 
						|
  partly initialized, or partly destroyed. If a resource is
 | 
						|
  destroyed, it is marked as that in case the destory failed and
 | 
						|
  being called again later.
 | 
						|
 | 
						|
  @param[in]  IpSb               The IP4 serviceing binding instance to clean up
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The resource used by the instance are cleaned up
 | 
						|
  @retval other                  Failed to clean up some of the resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ip4CleanService (
 | 
						|
  IN IP4_SERVICE            *IpSb
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  if (IpSb->DefaultInterface != NULL) {
 | 
						|
    Status = Ip4FreeInterface (IpSb->DefaultInterface, NULL);
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    IpSb->DefaultInterface = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IpSb->DefaultRouteTable != NULL) {
 | 
						|
    Ip4FreeRouteTable (IpSb->DefaultRouteTable);
 | 
						|
    IpSb->DefaultRouteTable = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  Ip4CleanAssembleTable (&IpSb->Assemble);
 | 
						|
 | 
						|
  if (IpSb->MnpChildHandle != NULL) {
 | 
						|
    if (IpSb->Mnp != NULL) {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             IpSb->MnpChildHandle,
 | 
						|
             &gEfiManagedNetworkProtocolGuid,
 | 
						|
             IpSb->Image,
 | 
						|
             IpSb->Controller
 | 
						|
             );
 | 
						|
 | 
						|
      IpSb->Mnp = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    NetLibDestroyServiceChild (
 | 
						|
      IpSb->Controller,
 | 
						|
      IpSb->Image,
 | 
						|
      &gEfiManagedNetworkServiceBindingProtocolGuid,
 | 
						|
      IpSb->MnpChildHandle
 | 
						|
      );
 | 
						|
 | 
						|
    IpSb->MnpChildHandle = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IpSb->Timer != NULL) {
 | 
						|
    gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
 | 
						|
    gBS->CloseEvent (IpSb->Timer);
 | 
						|
 | 
						|
    IpSb->Timer = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IpSb->Ip4Config != NULL) {
 | 
						|
    IpSb->Ip4Config->Stop (IpSb->Ip4Config);
 | 
						|
 | 
						|
    gBS->CloseProtocol (
 | 
						|
          IpSb->Controller,
 | 
						|
          &gEfiIp4ConfigProtocolGuid,
 | 
						|
          IpSb->Image,
 | 
						|
          IpSb->Controller
 | 
						|
          );
 | 
						|
 | 
						|
    gBS->CloseEvent (IpSb->DoneEvent);
 | 
						|
    gBS->CloseEvent (IpSb->ReconfigEvent);
 | 
						|
    IpSb->ActiveEvent = NULL;
 | 
						|
    IpSb->Ip4Config = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Start this driver on ControllerHandle. This service is called by the
 | 
						|
  EFI boot service ConnectController(). In order to make
 | 
						|
  drivers as small as possible, there are a few calling restrictions for
 | 
						|
  this service. ConnectController() must follow these
 | 
						|
  calling restrictions. If any other agent wishes to call Start() it
 | 
						|
  must also follow these calling restrictions.
 | 
						|
 | 
						|
  @param[in]  This                 Protocol instance pointer.
 | 
						|
  @param[in]  ControllerHandle     Handle of device to bind driver to
 | 
						|
  @param[in]  RemainingDevicePath  Optional parameter use to pick a specific child
 | 
						|
                                   device to start.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          This driver is added to ControllerHandle
 | 
						|
  @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
 | 
						|
  @retval other                This driver does not support this device
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
Ip4DriverBindingStart (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL  * This,
 | 
						|
  IN EFI_HANDLE                   ControllerHandle,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  IP4_SERVICE               *IpSb;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Test for the Ip4 service binding protocol
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  ControllerHandle,
 | 
						|
                  &gEfiIp4ServiceBindingProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  ControllerHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (Status == EFI_SUCCESS) {
 | 
						|
    return EFI_ALREADY_STARTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Ip4CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Install the Ip4ServiceBinding Protocol onto ControlerHandle
 | 
						|
  //
 | 
						|
  Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                  &ControllerHandle,
 | 
						|
                  &gEfiIp4ServiceBindingProtocolGuid,
 | 
						|
                  &IpSb->ServiceBinding,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto FREE_SERVICE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // ready to go: start the receiving and timer
 | 
						|
  //
 | 
						|
  Status = Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto UNINSTALL_PROTOCOL;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->SetTimer (IpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto UNINSTALL_PROTOCOL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the IP4 ID
 | 
						|
  //
 | 
						|
  mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ());
 | 
						|
 | 
						|
  Ip4SetVariableData (IpSb);
 | 
						|
 | 
						|
  return Status;
 | 
						|
 | 
						|
UNINSTALL_PROTOCOL:
 | 
						|
  gBS->UninstallProtocolInterface (
 | 
						|
         ControllerHandle,
 | 
						|
         &gEfiIp4ServiceBindingProtocolGuid,
 | 
						|
         &IpSb->ServiceBinding
 | 
						|
         );
 | 
						|
 | 
						|
FREE_SERVICE:
 | 
						|
  Ip4CleanService (IpSb);
 | 
						|
  gBS->FreePool (IpSb);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Stop this driver on ControllerHandle. This service is called by the
 | 
						|
  EFI boot service DisconnectController(). In order to
 | 
						|
  make drivers as small as possible, there are a few calling
 | 
						|
  restrictions for this service. DisconnectController()
 | 
						|
  must follow these calling restrictions. If any other agent wishes
 | 
						|
  to call Stop() it must also follow these calling restrictions.
 | 
						|
  
 | 
						|
  @param[in]  This              Protocol instance pointer.
 | 
						|
  @param[in]  ControllerHandle  Handle of device to stop driver on
 | 
						|
  @param[in]  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number
 | 
						|
                                of children is zero stop the entire bus driver.
 | 
						|
  @param[in]  ChildHandleBuffer List of Child Handles to Stop.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           This driver is removed ControllerHandle
 | 
						|
  @retval other                 This driver was not removed from this device
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
Ip4DriverBindingStop (
 | 
						|
  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN  EFI_HANDLE                   ControllerHandle,
 | 
						|
  IN  UINTN                        NumberOfChildren,
 | 
						|
  IN  EFI_HANDLE                   *ChildHandleBuffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
 | 
						|
  IP4_SERVICE                   *IpSb;
 | 
						|
  IP4_PROTOCOL                  *IpInstance;
 | 
						|
  EFI_HANDLE                    NicHandle;
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  EFI_TPL                       OldTpl;
 | 
						|
  INTN                          State;
 | 
						|
  BOOLEAN                       IsArp;
 | 
						|
 | 
						|
  //
 | 
						|
  // IP4 driver opens the MNP child, ARP children or the IP4_CONFIG protocol
 | 
						|
  // by driver. So the ControllerHandle may be the MNP child handle, ARP child
 | 
						|
  // handle, or the NIC (UNDI) handle because IP4_CONFIG protocol is installed
 | 
						|
  // in the NIC handle.
 | 
						|
  //
 | 
						|
  //
 | 
						|
  // First, check whether it is the IP4_CONFIG protocol being uninstalled.
 | 
						|
  // IP4_CONFIG protocol is installed on the NIC handle. It isn't necessary
 | 
						|
  // to clean up the default configuration if IP4_CONFIG is being stopped.
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  ControllerHandle,
 | 
						|
                  &gEfiIp4ConfigProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  ControllerHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (Status == EFI_SUCCESS) {
 | 
						|
    //
 | 
						|
    // Retrieve the IP4 service binding protocol. If failed, it is
 | 
						|
    // likely that Ip4 ServiceBinding is uninstalled already. In this
 | 
						|
    // case, return immediately.
 | 
						|
    //
 | 
						|
    Status = gBS->OpenProtocol (
 | 
						|
                    ControllerHandle,
 | 
						|
                    &gEfiIp4ServiceBindingProtocolGuid,
 | 
						|
                    (VOID **) &ServiceBinding,
 | 
						|
                    This->DriverBindingHandle,
 | 
						|
                    ControllerHandle,
 | 
						|
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                    );
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
 | 
						|
 | 
						|
    OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
 | 
						|
    if (IpSb->Ip4Config != NULL && (IpSb->State != IP4_SERVICE_DESTORY)) {
 | 
						|
 | 
						|
      IpSb->Ip4Config->Stop (IpSb->Ip4Config);
 | 
						|
 | 
						|
      Status = gBS->CloseProtocol (
 | 
						|
                      ControllerHandle,
 | 
						|
                      &gEfiIp4ConfigProtocolGuid,
 | 
						|
                      IpSb->Image,
 | 
						|
                      ControllerHandle
 | 
						|
                      );
 | 
						|
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        gBS->RestoreTPL (OldTpl);
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // If the auto configure hasn't complete, mark it as not started.
 | 
						|
      //
 | 
						|
      if (IpSb->State == IP4_SERVICE_STARTED) {
 | 
						|
        IpSb->State = IP4_SERVICE_UNSTARTED;
 | 
						|
      }
 | 
						|
 | 
						|
      IpSb->Ip4Config = NULL;
 | 
						|
      gBS->CloseEvent (IpSb->DoneEvent);
 | 
						|
      gBS->CloseEvent (IpSb->ReconfigEvent);
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->RestoreTPL (OldTpl);
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Either MNP or ARP protocol is being uninstalled. The controller
 | 
						|
  // handle is either the MNP child or ARP child. But, the IP4's
 | 
						|
  // service binding is installed on the NIC handle. So, need to open
 | 
						|
  // the protocol info to find the NIC handle.
 | 
						|
  //
 | 
						|
  IsArp     = FALSE;
 | 
						|
  NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
 | 
						|
 | 
						|
  if (NicHandle == NULL) {
 | 
						|
    NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);
 | 
						|
    IsArp     = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NicHandle == NULL) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve the IP4 service binding protocol
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  NicHandle,
 | 
						|
                  &gEfiIp4ServiceBindingProtocolGuid,
 | 
						|
                  (VOID **) &ServiceBinding,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  NicHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  IpSb   = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
 | 
						|
  if (IpSb->InDestory) {
 | 
						|
    gBS->RestoreTPL (OldTpl);
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IsArp) {
 | 
						|
    while (!IsListEmpty (&IpSb->Children)) {
 | 
						|
      IpInstance = NET_LIST_HEAD (&IpSb->Children, IP4_PROTOCOL, Link);
 | 
						|
 | 
						|
      ServiceBinding->DestroyChild (ServiceBinding, IpInstance->Handle);
 | 
						|
    }
 | 
						|
 | 
						|
    if (IpSb->NumChildren != 0) {
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    IpSb->InDestory = TRUE;
 | 
						|
 | 
						|
    State           = IpSb->State;
 | 
						|
    IpSb->State     = IP4_SERVICE_DESTORY;
 | 
						|
 | 
						|
    //
 | 
						|
    // Clear the variable data.
 | 
						|
    //
 | 
						|
    Ip4ClearVariableData (IpSb);
 | 
						|
 | 
						|
    //
 | 
						|
    // OK, clean other resources then uninstall the service binding protocol.
 | 
						|
    //
 | 
						|
    Status = Ip4CleanService (IpSb);
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      IpSb->State = State;
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->UninstallProtocolInterface (
 | 
						|
           NicHandle,
 | 
						|
           &gEfiIp4ServiceBindingProtocolGuid,
 | 
						|
           ServiceBinding
 | 
						|
           );
 | 
						|
 | 
						|
    gBS->FreePool (IpSb);
 | 
						|
  } else if (NumberOfChildren == 0) {
 | 
						|
    IpSb->InDestory = TRUE;
 | 
						|
 | 
						|
    State           = IpSb->State;
 | 
						|
    IpSb->State     = IP4_SERVICE_DESTORY;
 | 
						|
 | 
						|
    //
 | 
						|
    // Clear the variable data.
 | 
						|
    //
 | 
						|
    Ip4ClearVariableData (IpSb);
 | 
						|
 | 
						|
    //
 | 
						|
    // OK, clean other resources then uninstall the service binding protocol.
 | 
						|
    //
 | 
						|
    Status = Ip4CleanService (IpSb);
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      IpSb->State = State;
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->UninstallProtocolInterface (
 | 
						|
           NicHandle,
 | 
						|
           &gEfiIp4ServiceBindingProtocolGuid,
 | 
						|
           ServiceBinding
 | 
						|
           );
 | 
						|
 | 
						|
    gBS->FreePool (IpSb);
 | 
						|
  } else {
 | 
						|
 | 
						|
    while (!IsListEmpty (&IpSb->Children)) {
 | 
						|
      IpInstance = NET_LIST_HEAD (&IpSb->Children, IP4_PROTOCOL, Link);
 | 
						|
 | 
						|
      ServiceBinding->DestroyChild (ServiceBinding, IpInstance->Handle);
 | 
						|
    }
 | 
						|
 | 
						|
    if (IpSb->NumChildren != 0) {
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Creates a child handle and installs a protocol.
 | 
						|
  
 | 
						|
  The CreateChild() function installs a protocol on ChildHandle. 
 | 
						|
  If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle. 
 | 
						|
  If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
 | 
						|
 | 
						|
  @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
 | 
						|
  @param  ChildHandle 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_SUCCES            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
 | 
						|
Ip4ServiceBindingCreateChild (
 | 
						|
  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
 | 
						|
  IN OUT EFI_HANDLE                *ChildHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  IP4_SERVICE               *IpSb;
 | 
						|
  IP4_PROTOCOL              *IpInstance;
 | 
						|
  EFI_TPL                   OldTpl;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  VOID                      *Mnp;
 | 
						|
 | 
						|
  if ((This == NULL) || (ChildHandle == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  IpSb       = IP4_SERVICE_FROM_PROTOCOL (This);
 | 
						|
  IpInstance = AllocatePool (sizeof (IP4_PROTOCOL));
 | 
						|
 | 
						|
  if (IpInstance == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Ip4InitProtocol (IpSb, IpInstance);
 | 
						|
 | 
						|
  //
 | 
						|
  // Install Ip4 onto ChildHandle
 | 
						|
  //
 | 
						|
  Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                  ChildHandle,
 | 
						|
                  &gEfiIp4ProtocolGuid,
 | 
						|
                  &IpInstance->Ip4Proto,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  IpInstance->Handle = *ChildHandle;
 | 
						|
 | 
						|
  //
 | 
						|
  // Open the Managed Network protocol BY_CHILD.
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  IpSb->MnpChildHandle,
 | 
						|
                  &gEfiManagedNetworkProtocolGuid,
 | 
						|
                  (VOID **) &Mnp,
 | 
						|
                  gIp4DriverBinding.DriverBindingHandle,
 | 
						|
                  IpInstance->Handle,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->UninstallMultipleProtocolInterfaces (
 | 
						|
           ChildHandle,
 | 
						|
           &gEfiIp4ProtocolGuid,
 | 
						|
           &IpInstance->Ip4Proto,
 | 
						|
           NULL
 | 
						|
           );
 | 
						|
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Insert it into the service binding instance.
 | 
						|
  //
 | 
						|
  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
 | 
						|
  InsertTailList (&IpSb->Children, &IpInstance->Link);
 | 
						|
  IpSb->NumChildren++;
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
 | 
						|
    Ip4CleanProtocol (IpInstance);
 | 
						|
 | 
						|
    gBS->FreePool (IpInstance);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  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  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
 | 
						|
  @param  ChildHandle Handle of the child to destroy
 | 
						|
 | 
						|
  @retval EFI_SUCCES            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
 | 
						|
Ip4ServiceBindingDestroyChild (
 | 
						|
  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
 | 
						|
  IN EFI_HANDLE                    ChildHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  IP4_SERVICE               *IpSb;
 | 
						|
  IP4_PROTOCOL              *IpInstance;
 | 
						|
  EFI_IP4_PROTOCOL          *Ip4;
 | 
						|
  EFI_TPL                   OldTpl;
 | 
						|
  INTN                      State;
 | 
						|
 | 
						|
  if ((This == NULL) || (ChildHandle == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve the private context data structures
 | 
						|
  //
 | 
						|
  IpSb   = IP4_SERVICE_FROM_PROTOCOL (This);
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  ChildHandle,
 | 
						|
                  &gEfiIp4ProtocolGuid,
 | 
						|
                  (VOID **) &Ip4,
 | 
						|
                  gIp4DriverBinding.DriverBindingHandle,
 | 
						|
                  ChildHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);
 | 
						|
 | 
						|
  if (IpInstance->Service != IpSb) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
 | 
						|
  //
 | 
						|
  // A child can be destoried more than once. For example,
 | 
						|
  // Ip4DriverBindingStop will destory all of its children.
 | 
						|
  // when UDP driver is being stopped, it will destory all
 | 
						|
  // the IP child it opens.
 | 
						|
  //
 | 
						|
  if (IpInstance->State == IP4_STATE_DESTORY) {
 | 
						|
    gBS->RestoreTPL (OldTpl);
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  State             = IpInstance->State;
 | 
						|
  IpInstance->State = IP4_STATE_DESTORY;
 | 
						|
 | 
						|
  //
 | 
						|
  // Close the Managed Network protocol.
 | 
						|
  //
 | 
						|
  gBS->CloseProtocol (
 | 
						|
         IpSb->MnpChildHandle,
 | 
						|
         &gEfiManagedNetworkProtocolGuid,
 | 
						|
         gIp4DriverBinding.DriverBindingHandle,
 | 
						|
         ChildHandle
 | 
						|
         );
 | 
						|
 | 
						|
  //
 | 
						|
  // Uninstall the IP4 protocol first. Many thing happens during
 | 
						|
  // this:
 | 
						|
  // 1. The consumer of the IP4 protocol will be stopped if it
 | 
						|
  // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
 | 
						|
  // stopped, IP driver's stop function will be called, and uninstall
 | 
						|
  // EFI_IP4_PROTOCOL will trigger the UDP's stop function. This
 | 
						|
  // makes it possible to create the network stack bottom up, and
 | 
						|
  // stop it top down.
 | 
						|
  // 2. the upper layer will recycle the received packet. The recycle
 | 
						|
  // event's TPL is higher than this function. The recycle events
 | 
						|
  // will be called back before preceeding. If any packets not recycled,
 | 
						|
  // that means there is a resource leak.
 | 
						|
  //
 | 
						|
  Status = gBS->UninstallProtocolInterface (
 | 
						|
                  ChildHandle,
 | 
						|
                  &gEfiIp4ProtocolGuid,
 | 
						|
                  &IpInstance->Ip4Proto
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Ip4CleanProtocol (IpInstance);
 | 
						|
 | 
						|
  Ip4SetVariableData (IpSb);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->InstallMultipleProtocolInterfaces (
 | 
						|
           &ChildHandle,
 | 
						|
           &gEfiIp4ProtocolGuid,
 | 
						|
           Ip4,
 | 
						|
           NULL
 | 
						|
           );
 | 
						|
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  RemoveEntryList (&IpInstance->Link);
 | 
						|
  IpSb->NumChildren--;
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  gBS->FreePool (IpInstance);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
  IpInstance->State = State;
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |