Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Samer El-Haj-Mahmoud <elhaj@hp.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Tian Feng <feng.tian@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16465 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			746 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			746 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  This code implements the IP4Config and NicIp4Config protocols.
 | 
						|
 | 
						|
Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
 | 
						|
Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
 | 
						|
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<BR>
 | 
						|
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 "Ip4Config.h"
 | 
						|
#include "NicIp4Variable.h"
 | 
						|
 | 
						|
//
 | 
						|
// Ip4 Config Protocol
 | 
						|
//
 | 
						|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_PROTOCOL     mIp4ConfigProtocolTemplate = {
 | 
						|
  EfiIp4ConfigStart,
 | 
						|
  EfiIp4ConfigStop,
 | 
						|
  EfiIp4ConfigGetData
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Get the NIC's configure information from the IP4 configure variable.
 | 
						|
  It will remove the invalid variable.
 | 
						|
 | 
						|
  @param  Instance               The IP4 CONFIG instance.
 | 
						|
 | 
						|
  @return NULL if no configure for the NIC in the variable, or it is invalid.
 | 
						|
          Otherwise the pointer to the NIC's IP configure parameter will be returned.
 | 
						|
 | 
						|
**/
 | 
						|
NIC_IP4_CONFIG_INFO *
 | 
						|
EfiNicIp4ConfigGetInfo (
 | 
						|
  IN  IP4_CONFIG_INSTANCE   *Instance
 | 
						|
  )
 | 
						|
{
 | 
						|
  NIC_IP4_CONFIG_INFO *NicConfig;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read the configuration parameter for this NIC from
 | 
						|
  // the EFI variable
 | 
						|
  //
 | 
						|
  NicConfig = Ip4ConfigReadVariable (Instance);
 | 
						|
  if (NicConfig == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate the configuration, if the configuration is invalid,
 | 
						|
  // remove it from the variable.
 | 
						|
  //
 | 
						|
  if (!Ip4ConfigIsValid (NicConfig)) {
 | 
						|
    Ip4ConfigWriteVariable (Instance, NULL);
 | 
						|
 | 
						|
    FreePool (NicConfig);
 | 
						|
    NicConfig = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  return NicConfig;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set the IP configure parameters for this NIC.
 | 
						|
 | 
						|
  If Reconfig is TRUE, the IP driver will be informed to discard current
 | 
						|
  auto configure parameter and restart the auto configuration process.
 | 
						|
  If current there is a pending auto configuration, EFI_ALREADY_STARTED is
 | 
						|
  returned. You can only change the configure setting when either
 | 
						|
  the configure has finished or not started yet. If NicConfig, the
 | 
						|
  NIC's configure parameter is removed from the variable.
 | 
						|
 | 
						|
  @param  Instance               The IP4 CONFIG instance.
 | 
						|
  @param  NicConfig              The new NIC IP4 configure parameter.
 | 
						|
  @param  Reconfig               Inform the IP4 driver to restart the auto
 | 
						|
                                 configuration.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The configure parameter for this NIC was
 | 
						|
                                 set successfully.
 | 
						|
  @retval EFI_INVALID_PARAMETER  This is NULL or the configure parameter is
 | 
						|
                                 invalid.
 | 
						|
  @retval EFI_ALREADY_STARTED    There is a pending auto configuration.
 | 
						|
  @retval EFI_NOT_FOUND          No auto configure parameter is found.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiNicIp4ConfigSetInfo (
 | 
						|
  IN IP4_CONFIG_INSTANCE          *Instance,
 | 
						|
  IN NIC_IP4_CONFIG_INFO          *NicConfig     OPTIONAL,
 | 
						|
  IN BOOLEAN                      Reconfig
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate the parameters
 | 
						|
  //
 | 
						|
  if (Instance == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((NicConfig != NULL) && (!Ip4ConfigIsValid (NicConfig) ||
 | 
						|
      !NIC_ADDR_EQUAL (&NicConfig->NicAddr, &Instance->NicAddr))) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Instance->State == IP4_CONFIG_STATE_STARTED) {
 | 
						|
    return EFI_ALREADY_STARTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Update the parameter in the configure variable
 | 
						|
  //
 | 
						|
  Status = Ip4ConfigWriteVariable (Instance, NicConfig);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Signal the IP4 to run the auto configuration again
 | 
						|
  //
 | 
						|
  if (Reconfig && (Instance->ReconfigEvent != NULL)) {
 | 
						|
    //
 | 
						|
    // When NicConfig is NULL, NIC IP4 configuration parameter is removed,
 | 
						|
    // the auto configuration process should stop running the configuration
 | 
						|
    // policy for the EFI IPv4 Protocol driver.
 | 
						|
    //
 | 
						|
    if (NicConfig == NULL) {
 | 
						|
      Instance->DoNotStart = TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = gBS->SignalEvent (Instance->ReconfigEvent);
 | 
						|
    DispatchDpc ();
 | 
						|
  }
 | 
						|
 | 
						|
  if (NicConfig == NULL) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // A dedicated timer is used to poll underlying media status.In case of
 | 
						|
  // cable swap, a new round auto configuration will be initiated. The timer
 | 
						|
  // starts in DHCP policy only. STATIC policy stops the timer.
 | 
						|
  // 
 | 
						|
  if (NicConfig->Source == IP4_CONFIG_SOURCE_DHCP) {
 | 
						|
    gBS->SetTimer (Instance->Timer, TimerPeriodic, TICKS_PER_SECOND);
 | 
						|
  } else if (NicConfig->Source == IP4_CONFIG_SOURCE_STATIC) {
 | 
						|
    gBS->SetTimer (Instance->Timer, TimerCancel, 0);
 | 
						|
  }
 | 
						|
  
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Callback function when DHCP process finished. It will save the
 | 
						|
  retrieved IP configure parameter from DHCP to the NVRam.
 | 
						|
 | 
						|
  @param  Event                  The callback event
 | 
						|
  @param  Context                Opaque context to the callback
 | 
						|
 | 
						|
  @return None
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
Ip4ConfigOnDhcp4Complete (
 | 
						|
  IN EFI_EVENT              Event,
 | 
						|
  IN VOID                   *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  IP4_CONFIG_INSTANCE       *Instance;
 | 
						|
  EFI_DHCP4_MODE_DATA       Dhcp4Mode;
 | 
						|
  EFI_IP4_IPCONFIG_DATA     *Ip4Config;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  BOOLEAN                   Permanent;
 | 
						|
  IP4_ADDR                  Subnet;
 | 
						|
  IP4_ADDR                  Ip1;
 | 
						|
  IP4_ADDR                  Ip2;
 | 
						|
 | 
						|
  Instance = (IP4_CONFIG_INSTANCE *) Context;
 | 
						|
  ASSERT (Instance->Dhcp4 != NULL);
 | 
						|
 | 
						|
  Instance->State   = IP4_CONFIG_STATE_CONFIGURED;
 | 
						|
  Instance->Result  = EFI_TIMEOUT;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the DHCP retrieved parameters
 | 
						|
  //
 | 
						|
  Status = Instance->Dhcp4->GetModeData (Instance->Dhcp4, &Dhcp4Mode);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Dhcp4Mode.State == Dhcp4Bound) {
 | 
						|
    //
 | 
						|
    // Save the new configuration retrieved by DHCP both in
 | 
						|
    // the instance and to NVRam. So, both the IP4 driver and
 | 
						|
    // other user can get that address.
 | 
						|
    //
 | 
						|
    Permanent = FALSE;
 | 
						|
 | 
						|
    if (Instance->NicConfig != NULL) {
 | 
						|
      ASSERT (Instance->NicConfig->Source == IP4_CONFIG_SOURCE_DHCP);
 | 
						|
      Permanent = Instance->NicConfig->Permanent;
 | 
						|
      FreePool (Instance->NicConfig);
 | 
						|
    }
 | 
						|
 | 
						|
    Instance->NicConfig = AllocatePool (sizeof (NIC_IP4_CONFIG_INFO) + 2* sizeof (EFI_IP4_ROUTE_TABLE));
 | 
						|
 | 
						|
    if (Instance->NicConfig == NULL) {
 | 
						|
      Instance->Result = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto ON_EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    Instance->NicConfig->Ip4Info.RouteTable = (EFI_IP4_ROUTE_TABLE *) (Instance->NicConfig + 1);
 | 
						|
 | 
						|
    CopyMem (&Instance->NicConfig->NicAddr, &Instance->NicAddr, sizeof (Instance->NicConfig->NicAddr));
 | 
						|
    Instance->NicConfig->Source  = IP4_CONFIG_SOURCE_DHCP;
 | 
						|
    Instance->NicConfig->Permanent = Permanent;
 | 
						|
 | 
						|
    Ip4Config                    = &Instance->NicConfig->Ip4Info;
 | 
						|
    Ip4Config->StationAddress    = Dhcp4Mode.ClientAddress;
 | 
						|
    Ip4Config->SubnetMask        = Dhcp4Mode.SubnetMask;
 | 
						|
 | 
						|
    //
 | 
						|
    // Create a route for the connected network
 | 
						|
    //
 | 
						|
    Ip4Config->RouteTableSize    = 1;
 | 
						|
 | 
						|
    CopyMem (&Ip1, &Dhcp4Mode.ClientAddress, sizeof (IP4_ADDR));
 | 
						|
    CopyMem (&Ip2, &Dhcp4Mode.SubnetMask, sizeof (IP4_ADDR));
 | 
						|
 | 
						|
    Subnet = Ip1 & Ip2;
 | 
						|
 | 
						|
    CopyMem (&Ip4Config->RouteTable[0].SubnetAddress, &Subnet, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
    CopyMem (&Ip4Config->RouteTable[0].SubnetMask, &Dhcp4Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
    ZeroMem (&Ip4Config->RouteTable[0].GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
 | 
						|
    //
 | 
						|
    // Create a route if there is a default router.
 | 
						|
    //
 | 
						|
    if (!EFI_IP4_EQUAL (&Dhcp4Mode.RouterAddress, &mZeroIp4Addr)) {
 | 
						|
      Ip4Config->RouteTableSize = 2;
 | 
						|
 | 
						|
      ZeroMem (&Ip4Config->RouteTable[1].SubnetAddress, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
      ZeroMem (&Ip4Config->RouteTable[1].SubnetMask, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
      CopyMem (&Ip4Config->RouteTable[1].GatewayAddress, &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
    }
 | 
						|
 | 
						|
    Instance->Result = EFI_SUCCESS;
 | 
						|
 | 
						|
    //
 | 
						|
    // ignore the return status of EfiNicIp4ConfigSetInfo. Network
 | 
						|
    // stack can operate even that failed.
 | 
						|
    //
 | 
						|
    EfiNicIp4ConfigSetInfo (Instance, Instance->NicConfig, FALSE);
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->SignalEvent (Instance->DoneEvent);
 | 
						|
  Ip4ConfigCleanDhcp4 (Instance);
 | 
						|
 | 
						|
  DispatchDpc ();
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Starts running the configuration policy for the EFI IPv4 Protocol driver.
 | 
						|
 | 
						|
  The Start() function is called to determine and to begin the platform
 | 
						|
  configuration policy by the EFI IPv4 Protocol driver. This determination may
 | 
						|
  be as simple as returning EFI_UNSUPPORTED if there is no EFI IPv4 Protocol
 | 
						|
  driver configuration policy. It may be as involved as loading some defaults
 | 
						|
  from nonvolatile storage, downloading dynamic data from a DHCP server, and
 | 
						|
  checking permissions with a site policy server.
 | 
						|
  Starting the configuration policy is just the beginning. It may finish almost
 | 
						|
  instantly or it may take several minutes before it fails to retrieve configuration
 | 
						|
  information from one or more servers. Once the policy is started, drivers
 | 
						|
  should use the DoneEvent parameter to determine when the configuration policy
 | 
						|
  has completed. EFI_IP4_CONFIG_PROTOCOL.GetData() must then be called to
 | 
						|
  determine if the configuration succeeded or failed.
 | 
						|
  Until the configuration completes successfully, EFI IPv4 Protocol driver instances
 | 
						|
  that are attempting to use default configurations must return EFI_NO_MAPPING.
 | 
						|
  Once the configuration is complete, the EFI IPv4 Configuration Protocol driver
 | 
						|
  signals DoneEvent. The configuration may need to be updated in the future,
 | 
						|
  however; in this case, the EFI IPv4 Configuration Protocol driver must signal
 | 
						|
  ReconfigEvent, and all EFI IPv4 Protocol driver instances that are using default
 | 
						|
  configurations must return EFI_NO_MAPPING until the configuration policy has
 | 
						|
  been rerun.
 | 
						|
 | 
						|
  @param  This                   Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
 | 
						|
  @param  DoneEvent              Event that will be signaled when the EFI IPv4
 | 
						|
                                 Protocol driver configuration policy completes
 | 
						|
                                 execution. This event must be of type EVT_NOTIFY_SIGNAL.
 | 
						|
  @param  ReconfigEvent          Event that will be signaled when the EFI IPv4
 | 
						|
                                 Protocol driver configuration needs to be updated.
 | 
						|
                                 This event must be of type EVT_NOTIFY_SIGNAL.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The configuration policy for the EFI IPv4 Protocol
 | 
						|
                                 driver is now running.
 | 
						|
  @retval EFI_INVALID_PARAMETER  One or more of the following parameters is NULL:
 | 
						|
                                  This
 | 
						|
                                  DoneEvent
 | 
						|
                                  ReconfigEvent
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Required system resources could not be allocated.
 | 
						|
  @retval EFI_ALREADY_STARTED    The configuration policy for the EFI IPv4 Protocol
 | 
						|
                                 driver was already started.
 | 
						|
  @retval EFI_DEVICE_ERROR       An unexpected system error or network error occurred.
 | 
						|
  @retval EFI_UNSUPPORTED        This interface does not support the EFI IPv4 Protocol
 | 
						|
                                 driver configuration.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiIp4ConfigStart (
 | 
						|
  IN EFI_IP4_CONFIG_PROTOCOL  *This,
 | 
						|
  IN EFI_EVENT                DoneEvent,
 | 
						|
  IN EFI_EVENT                ReconfigEvent
 | 
						|
  )
 | 
						|
{
 | 
						|
  IP4_CONFIG_INSTANCE       *Instance;
 | 
						|
  EFI_DHCP4_PROTOCOL        *Dhcp4;
 | 
						|
  EFI_DHCP4_MODE_DATA       Dhcp4Mode;
 | 
						|
  EFI_DHCP4_PACKET_OPTION   *OptionList[1];
 | 
						|
  IP4_CONFIG_DHCP4_OPTION   ParaList;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  UINT32                    Source;
 | 
						|
  EFI_TPL                   OldTpl;
 | 
						|
 | 
						|
  if ((This == NULL) || (DoneEvent == NULL) || (ReconfigEvent == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance = IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This);
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
 | 
						|
  if (Instance->State != IP4_CONFIG_STATE_IDLE) {
 | 
						|
    Status = EFI_ALREADY_STARTED;
 | 
						|
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance->DoneEvent     = DoneEvent;
 | 
						|
  Instance->ReconfigEvent = ReconfigEvent;
 | 
						|
 | 
						|
  Instance->NicConfig     = EfiNicIp4ConfigGetInfo (Instance);
 | 
						|
 | 
						|
  if (Instance->NicConfig == NULL) {
 | 
						|
    if (Instance->DoNotStart) {
 | 
						|
      Instance->DoNotStart = FALSE;
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
      goto ON_EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    Source = IP4_CONFIG_SOURCE_DHCP;
 | 
						|
  } else {
 | 
						|
    Source = Instance->NicConfig->Source;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If the source is static, the auto configuration is done.
 | 
						|
  // return now.
 | 
						|
  //
 | 
						|
  if (Source == IP4_CONFIG_SOURCE_STATIC) {
 | 
						|
    Instance->State  = IP4_CONFIG_STATE_CONFIGURED;
 | 
						|
    Instance->Result = EFI_SUCCESS;
 | 
						|
 | 
						|
    gBS->SignalEvent (Instance->DoneEvent);
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Start the dhcp process
 | 
						|
  //
 | 
						|
  ASSERT ((Source == IP4_CONFIG_SOURCE_DHCP) && (Instance->Dhcp4 == NULL));
 | 
						|
 | 
						|
  Status = NetLibCreateServiceChild (
 | 
						|
             Instance->Controller,
 | 
						|
             Instance->Image,
 | 
						|
             &gEfiDhcp4ServiceBindingProtocolGuid,
 | 
						|
             &Instance->Dhcp4Handle
 | 
						|
             );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Instance->Dhcp4Handle,
 | 
						|
                  &gEfiDhcp4ProtocolGuid,
 | 
						|
                  (VOID **) &Instance->Dhcp4,
 | 
						|
                  Instance->Image,
 | 
						|
                  Instance->Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the current DHCP status, if the DHCP process has
 | 
						|
  // already finished, return now.
 | 
						|
  //
 | 
						|
  Dhcp4  = Instance->Dhcp4;
 | 
						|
  Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Dhcp4Mode.State == Dhcp4Bound) {
 | 
						|
    Ip4ConfigOnDhcp4Complete (NULL, Instance);
 | 
						|
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Try to start the DHCP process. Use most of the current
 | 
						|
  // DHCP configuration to avoid problems if some DHCP client
 | 
						|
  // yields the control of this DHCP service to us.
 | 
						|
  //
 | 
						|
  ParaList.Head.OpCode             = DHCP_TAG_PARA_LIST;
 | 
						|
  ParaList.Head.Length             = 2;
 | 
						|
  ParaList.Head.Data[0]            = DHCP_TAG_NETMASK;
 | 
						|
  ParaList.Route                   = DHCP_TAG_ROUTER;
 | 
						|
  OptionList[0]                    = &ParaList.Head;
 | 
						|
  Dhcp4Mode.ConfigData.OptionCount = 1;
 | 
						|
  Dhcp4Mode.ConfigData.OptionList  = OptionList;
 | 
						|
 | 
						|
  Status = Dhcp4->Configure (Dhcp4, &Dhcp4Mode.ConfigData);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Start the DHCP process
 | 
						|
  //
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_CALLBACK,
 | 
						|
                  Ip4ConfigOnDhcp4Complete,
 | 
						|
                  Instance,
 | 
						|
                  &Instance->Dhcp4Event
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Dhcp4->Start (Dhcp4, Instance->Dhcp4Event);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance->State  = IP4_CONFIG_STATE_STARTED;
 | 
						|
  Instance->Result = EFI_NOT_READY;
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Ip4ConfigCleanConfig (Instance);
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  DispatchDpc ();
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Stops running the configuration policy for the EFI IPv4 Protocol driver.
 | 
						|
 | 
						|
  The Stop() function stops the configuration policy for the EFI IPv4 Protocol driver.
 | 
						|
  All configuration data will be lost after calling Stop().
 | 
						|
 | 
						|
  @param  This                   Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The configuration policy for the EFI IPv4 Protocol
 | 
						|
                                 driver has been stopped.
 | 
						|
  @retval EFI_INVALID_PARAMETER  This is NULL.
 | 
						|
  @retval EFI_NOT_STARTED        The configuration policy for the EFI IPv4 Protocol
 | 
						|
                                 driver was not started.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiIp4ConfigStop (
 | 
						|
  IN EFI_IP4_CONFIG_PROTOCOL  *This
 | 
						|
  )
 | 
						|
{
 | 
						|
  IP4_CONFIG_INSTANCE  *Instance;
 | 
						|
  EFI_STATUS           Status;
 | 
						|
  EFI_TPL              OldTpl;
 | 
						|
 | 
						|
  if (This == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance = IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This);
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
 | 
						|
  if (Instance->State == IP4_CONFIG_STATE_IDLE) {
 | 
						|
    Status = EFI_NOT_STARTED;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Release all the configure parameters. Don't signal the user
 | 
						|
  // event. The user wants to abort the configuration, this isn't
 | 
						|
  // the configuration done or reconfiguration.
 | 
						|
  //
 | 
						|
  Ip4ConfigCleanConfig (Instance);
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Returns the default configuration data (if any) for the EFI IPv4 Protocol driver.
 | 
						|
 | 
						|
  The GetData() function returns the current configuration data for the EFI IPv4
 | 
						|
  Protocol driver after the configuration policy has completed.
 | 
						|
 | 
						|
  @param  This                   Pointer to the EFI_IP4_CONFIG_PROTOCOL instance.
 | 
						|
  @param  ConfigDataSize         On input, the size of the ConfigData buffer.
 | 
						|
                                 On output, the count of bytes that were written
 | 
						|
                                 into the ConfigData buffer.
 | 
						|
  @param  ConfigData             Pointer to the EFI IPv4 Configuration Protocol
 | 
						|
                                 driver configuration data structure.
 | 
						|
                                 Type EFI_IP4_IPCONFIG_DATA is defined in
 | 
						|
                                 "Related Definitions" below.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The EFI IPv4 Protocol driver configuration has been returned.
 | 
						|
  @retval EFI_INVALID_PARAMETER  This is NULL.
 | 
						|
  @retval EFI_NOT_STARTED        The configuration policy for the EFI IPv4 Protocol
 | 
						|
                                 driver is not running.
 | 
						|
  @retval EFI_NOT_READY          EFI IPv4 Protocol driver configuration is still running.
 | 
						|
  @retval EFI_ABORTED            EFI IPv4 Protocol driver configuration could not complete.
 | 
						|
                                 Currently not implemented.
 | 
						|
  @retval EFI_BUFFER_TOO_SMALL   *ConfigDataSize is smaller than the configuration
 | 
						|
                                 data buffer or ConfigData is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiIp4ConfigGetData (
 | 
						|
  IN  EFI_IP4_CONFIG_PROTOCOL *This,
 | 
						|
  IN  OUT  UINTN              *ConfigDataSize,
 | 
						|
  OUT EFI_IP4_IPCONFIG_DATA   *ConfigData           OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  IP4_CONFIG_INSTANCE       *Instance;
 | 
						|
  NIC_IP4_CONFIG_INFO       *NicConfig;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_TPL                   OldTpl;
 | 
						|
  UINTN                     Len;
 | 
						|
 | 
						|
  if ((This == NULL) || (ConfigDataSize == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance  = IP4_CONFIG_INSTANCE_FROM_IP4CONFIG (This);
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
 | 
						|
  if (Instance->State == IP4_CONFIG_STATE_IDLE) {
 | 
						|
    Status = EFI_NOT_STARTED;
 | 
						|
  } else if (Instance->State == IP4_CONFIG_STATE_STARTED) {
 | 
						|
    Status = EFI_NOT_READY;
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy the configure data if auto configuration succeeds.
 | 
						|
  //
 | 
						|
  Status = Instance->Result;
 | 
						|
 | 
						|
  if (Status == EFI_SUCCESS) {
 | 
						|
    ASSERT (Instance->NicConfig != NULL);
 | 
						|
 | 
						|
    NicConfig = Instance->NicConfig;
 | 
						|
    Len       = SIZEOF_IP4_CONFIG_INFO (&NicConfig->Ip4Info);
 | 
						|
 | 
						|
    if ((*ConfigDataSize < Len) || (ConfigData == NULL)) {
 | 
						|
      Status = EFI_BUFFER_TOO_SMALL;
 | 
						|
    } else {
 | 
						|
      CopyMem (ConfigData, &NicConfig->Ip4Info, Len);
 | 
						|
      Ip4ConfigFixRouteTablePointer (ConfigData);
 | 
						|
    }
 | 
						|
 | 
						|
    *ConfigDataSize = Len;
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Release all the DHCP related resources.
 | 
						|
 | 
						|
  @param  This                   The IP4 configure instance
 | 
						|
 | 
						|
  @return None
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
Ip4ConfigCleanDhcp4 (
 | 
						|
  IN IP4_CONFIG_INSTANCE    *This
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (This->Dhcp4 != NULL) {
 | 
						|
    This->Dhcp4->Stop (This->Dhcp4);
 | 
						|
 | 
						|
    gBS->CloseProtocol (
 | 
						|
          This->Dhcp4Handle,
 | 
						|
          &gEfiDhcp4ProtocolGuid,
 | 
						|
          This->Image,
 | 
						|
          This->Controller
 | 
						|
          );
 | 
						|
 | 
						|
    This->Dhcp4 = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (This->Dhcp4Handle != NULL) {
 | 
						|
    NetLibDestroyServiceChild (
 | 
						|
      This->Controller,
 | 
						|
      This->Image,
 | 
						|
      &gEfiDhcp4ServiceBindingProtocolGuid,
 | 
						|
      This->Dhcp4Handle
 | 
						|
      );
 | 
						|
 | 
						|
    This->Dhcp4Handle = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (This->Dhcp4Event != NULL) {
 | 
						|
    gBS->CloseEvent (This->Dhcp4Event);
 | 
						|
    This->Dhcp4Event = NULL;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Clean up all the configuration parameters.
 | 
						|
 | 
						|
  @param  Instance               The IP4 configure instance
 | 
						|
 | 
						|
  @return None
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
Ip4ConfigCleanConfig (
 | 
						|
  IN IP4_CONFIG_INSTANCE        *Instance
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (Instance->NicConfig != NULL) {
 | 
						|
    FreePool (Instance->NicConfig);
 | 
						|
    Instance->NicConfig = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance->State         = IP4_CONFIG_STATE_IDLE;
 | 
						|
  Instance->DoneEvent     = NULL;
 | 
						|
  Instance->ReconfigEvent = NULL;
 | 
						|
 | 
						|
  Ip4ConfigCleanDhcp4 (Instance);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  A dedicated timer is used to poll underlying media status. In case of
 | 
						|
  cable swap, a new round auto configuration will be initiated. The timer 
 | 
						|
  will signal the IP4 to run the auto configuration again. IP4 driver will free
 | 
						|
  old IP address related resource, such as route table and Interface, then
 | 
						|
  initiate a DHCP process by IP4Config->Start to acquire new IP, eventually
 | 
						|
  create route table for new IP address.
 | 
						|
 | 
						|
  @param[in]  Event                  The IP4 service instance's heart beat timer.
 | 
						|
  @param[in]  Context                The IP4 service instance.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
MediaChangeDetect (
 | 
						|
  IN EFI_EVENT              Event,
 | 
						|
  IN VOID                   *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN                      OldMediaPresent;
 | 
						|
  EFI_STATUS                   Status;
 | 
						|
  EFI_SIMPLE_NETWORK_MODE      SnpModeData;
 | 
						|
  IP4_CONFIG_INSTANCE         *Instance;  
 | 
						|
 | 
						|
  Instance = (IP4_CONFIG_INSTANCE *) Context;
 | 
						|
 | 
						|
  OldMediaPresent = Instance->MediaPresent;
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Get fresh mode data from MNP, since underlying media status may change
 | 
						|
  //
 | 
						|
  Status = Instance->Mnp->GetModeData (Instance->Mnp, NULL, &SnpModeData);
 | 
						|
  if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance->MediaPresent = SnpModeData.MediaPresent;
 | 
						|
  //
 | 
						|
  // Media transimit Unpresent to Present means new link movement is detected.
 | 
						|
  //
 | 
						|
  if (!OldMediaPresent && Instance->MediaPresent) {
 | 
						|
    //
 | 
						|
    // Signal the IP4 to run the auto configuration again. IP4 driver will free
 | 
						|
    // old IP address related resource, such as route table and Interface, then 
 | 
						|
    // initiate a DHCP round by IP4Config->Start to acquire new IP, eventually 
 | 
						|
    // create route table for new IP address.
 | 
						|
    //
 | 
						|
    if (Instance->ReconfigEvent != NULL) {
 | 
						|
      Status = gBS->SignalEvent (Instance->ReconfigEvent);
 | 
						|
      DispatchDpc ();
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |