2. Fix the driver binding Stop() hang issue in the network stack. 3. Add Ip4 raw data support. 4. Add iSCSI Dhcp option 60 support. Signed-off-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Ye Ting <ting.ye@intel.com> Reviewed-by: Ouyang Qian <qian.ouyang@intel.com> git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13995 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1774 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1774 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  This file implement the EFI_DHCP4_PROTOCOL interface.
 | 
						|
 | 
						|
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
 | 
						|
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 "Dhcp4Impl.h"
 | 
						|
 | 
						|
/**
 | 
						|
  Returns the current operating mode and cached data packet for the EFI DHCPv4 Protocol driver.
 | 
						|
 | 
						|
  The GetModeData() function returns the current operating mode and cached data
 | 
						|
  packet for the EFI DHCPv4 Protocol driver.
 | 
						|
 | 
						|
  @param[in]  This          Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param[out] Dhcp4ModeData Pointer to storage for the EFI_DHCP4_MODE_DATA structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The mode data was returned.
 | 
						|
  @retval EFI_INVALID_PARAMETER This is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4GetModeData (
 | 
						|
  IN  EFI_DHCP4_PROTOCOL    *This,
 | 
						|
  OUT EFI_DHCP4_MODE_DATA   *Dhcp4ModeData
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Initializes, changes, or resets the operational settings for the EFI DHCPv4 Protocol driver.
 | 
						|
 | 
						|
  The Configure() function is used to initialize, change, or reset the operational
 | 
						|
  settings of the EFI DHCPv4 Protocol driver for the communication device on which
 | 
						|
  the EFI DHCPv4 Service Binding Protocol is installed. This function can be
 | 
						|
  successfully called only if both of the following are true:
 | 
						|
  * This instance of the EFI DHCPv4 Protocol driver is in the Dhcp4Stopped, Dhcp4Init,
 | 
						|
    Dhcp4InitReboot, or Dhcp4Bound states.
 | 
						|
  * No other EFI DHCPv4 Protocol driver instance that is controlled by this EFI
 | 
						|
    DHCPv4 Service Binding Protocol driver instance has configured this EFI DHCPv4
 | 
						|
    Protocol driver.
 | 
						|
  When this driver is in the Dhcp4Stopped state, it can transfer into one of the
 | 
						|
  following two possible initial states:
 | 
						|
  * Dhcp4Init
 | 
						|
  * Dhcp4InitReboot
 | 
						|
  The driver can transfer into these states by calling Configure() with a non-NULL
 | 
						|
  Dhcp4CfgData. The driver will transfer into the appropriate state based on the
 | 
						|
  supplied client network address in the ClientAddress parameter and DHCP options
 | 
						|
  in the OptionList parameter as described in RFC 2131.
 | 
						|
  When Configure() is called successfully while Dhcp4CfgData is set to NULL, the
 | 
						|
  default configuring data will be reset in the EFI DHCPv4 Protocol driver and
 | 
						|
  the state of the EFI DHCPv4 Protocol driver will not be changed. If one instance
 | 
						|
  wants to make it possible for another instance to configure the EFI DHCPv4 Protocol
 | 
						|
  driver, it must call this function with Dhcp4CfgData set to NULL.
 | 
						|
 | 
						|
  @param[in]  This                   Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param[in]  Dhcp4CfgData           Pointer to the EFI_DHCP4_CONFIG_DATA.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The EFI DHCPv4 Protocol driver is now in the Dhcp4Init or
 | 
						|
                                Dhcp4InitReboot state, if the original state of this driver
 | 
						|
                                was Dhcp4Stopped and the value of Dhcp4CfgData was
 | 
						|
                                not NULL. Otherwise, the state was left unchanged.
 | 
						|
  @retval EFI_ACCESS_DENIED     This instance of the EFI DHCPv4 Protocol driver was not in the
 | 
						|
                                Dhcp4Stopped, Dhcp4Init, Dhcp4InitReboot, or Dhcp4Bound state;
 | 
						|
                                Or onother instance of this EFI DHCPv4 Protocol driver is already
 | 
						|
                                in a valid configured state.
 | 
						|
  @retval EFI_INVALID_PARAMETER Some parameter is NULL.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
 | 
						|
  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4Configure (
 | 
						|
  IN EFI_DHCP4_PROTOCOL     *This,
 | 
						|
  IN EFI_DHCP4_CONFIG_DATA  *Dhcp4CfgData       OPTIONAL
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Starts the DHCP configuration process.
 | 
						|
 | 
						|
  The Start() function starts the DHCP configuration process. This function can
 | 
						|
  be called only when the EFI DHCPv4 Protocol driver is in the Dhcp4Init or
 | 
						|
  Dhcp4InitReboot state.
 | 
						|
  If the DHCP process completes successfully, the state of the EFI DHCPv4 Protocol
 | 
						|
  driver will be transferred through Dhcp4Selecting and Dhcp4Requesting to the
 | 
						|
  Dhcp4Bound state. The CompletionEvent will then be signaled if it is not NULL.
 | 
						|
  If the process aborts, either by the user or by some unexpected network error,
 | 
						|
  the state is restored to the Dhcp4Init state. The Start() function can be called
 | 
						|
  again to restart the process.
 | 
						|
  Refer to RFC 2131 for precise state transitions during this process. At the
 | 
						|
  time when each event occurs in this process, the callback function that was set
 | 
						|
  by EFI_DHCP4_PROTOCOL.Configure() will be called and the user can take this
 | 
						|
  opportunity to control the process.
 | 
						|
 | 
						|
  @param[in]  This            Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param[in]  CompletionEvent If not NULL, indicates the event that will be signaled when the
 | 
						|
                              EFI DHCPv4 Protocol driver is transferred into the
 | 
						|
                              Dhcp4Bound state or when the DHCP process is aborted.
 | 
						|
                              EFI_DHCP4_PROTOCOL.GetModeData() can be called to
 | 
						|
                              check the completion status. If NULL,
 | 
						|
                              EFI_DHCP4_PROTOCOL.Start() will wait until the driver
 | 
						|
                              is transferred into the Dhcp4Bound state or the process fails.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The DHCP configuration process has started, or it has completed
 | 
						|
                                when CompletionEvent is NULL.
 | 
						|
  @retval EFI_NOT_STARTED       The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped
 | 
						|
                                state. EFI_DHCP4_PROTOCOL. Configure() needs to be called.
 | 
						|
  @retval EFI_INVALID_PARAMETER This is NULL.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
 | 
						|
  @retval EFI_TIMEOUT           The DHCP configuration process failed because no response was
 | 
						|
                                received from the server within the specified timeout value.
 | 
						|
  @retval EFI_ABORTED           The user aborted the DHCP process.
 | 
						|
  @retval EFI_ALREADY_STARTED   Some other EFI DHCPv4 Protocol instance already started the
 | 
						|
                                DHCP process.
 | 
						|
  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4Start (
 | 
						|
  IN EFI_DHCP4_PROTOCOL     *This,
 | 
						|
  IN EFI_EVENT              CompletionEvent   OPTIONAL
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Extends the lease time by sending a request packet.
 | 
						|
 | 
						|
  The RenewRebind() function is used to manually extend the lease time when the
 | 
						|
  EFI DHCPv4 Protocol driver is in the Dhcp4Bound state and the lease time has
 | 
						|
  not expired yet. This function will send a request packet to the previously
 | 
						|
  found server (or to any server when RebindRequest is TRUE) and transfer the
 | 
						|
  state into the Dhcp4Renewing state (or Dhcp4Rebinding when RebindingRequest is
 | 
						|
  TRUE). When a response is received, the state is returned to Dhcp4Bound.
 | 
						|
  If no response is received before the try count is exceeded (the RequestTryCount
 | 
						|
  field that is specified in EFI_DHCP4_CONFIG_DATA) but before the lease time that
 | 
						|
  was issued by the previous server expires, the driver will return to the Dhcp4Bound
 | 
						|
  state and the previous configuration is restored. The outgoing and incoming packets
 | 
						|
  can be captured by the EFI_DHCP4_CALLBACK function.
 | 
						|
 | 
						|
  @param[in]  This            Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param[in]  RebindRequest   If TRUE, this function broadcasts the request packets and enters
 | 
						|
                              the Dhcp4Rebinding state. Otherwise, it sends a unicast
 | 
						|
                              request packet and enters the Dhcp4Renewing state.
 | 
						|
  @param[in]  CompletionEvent If not NULL, this event is signaled when the renew/rebind phase
 | 
						|
                              completes or some error occurs.
 | 
						|
                              EFI_DHCP4_PROTOCOL.GetModeData() can be called to
 | 
						|
                              check the completion status. If NULL,
 | 
						|
                              EFI_DHCP4_PROTOCOL.RenewRebind() will busy-wait
 | 
						|
                              until the DHCP process finishes.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The EFI DHCPv4 Protocol driver is now in the
 | 
						|
                                Dhcp4Renewing state or is back to the Dhcp4Bound state.
 | 
						|
  @retval EFI_NOT_STARTED       The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped
 | 
						|
                                state. EFI_DHCP4_PROTOCOL.Configure() needs to
 | 
						|
                                be called.
 | 
						|
  @retval EFI_INVALID_PARAMETER This is NULL.
 | 
						|
  @retval EFI_TIMEOUT           There was no response from the server when the try count was
 | 
						|
                                exceeded.
 | 
						|
  @retval EFI_ACCESS_DENIED     The driver is not in the Dhcp4Bound state.
 | 
						|
  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4RenewRebind (
 | 
						|
  IN EFI_DHCP4_PROTOCOL     *This,
 | 
						|
  IN BOOLEAN                RebindRequest,
 | 
						|
  IN EFI_EVENT              CompletionEvent   OPTIONAL
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Releases the current address configuration.
 | 
						|
 | 
						|
  The Release() function releases the current configured IP address by doing either
 | 
						|
  of the following:
 | 
						|
  * Sending a DHCPRELEASE packet when the EFI DHCPv4 Protocol driver is in the
 | 
						|
    Dhcp4Bound state
 | 
						|
  * Setting the previously assigned IP address that was provided with the
 | 
						|
    EFI_DHCP4_PROTOCOL.Configure() function to 0.0.0.0 when the driver is in
 | 
						|
    Dhcp4InitReboot state
 | 
						|
  After a successful call to this function, the EFI DHCPv4 Protocol driver returns
 | 
						|
  to the Dhcp4Init state and any subsequent incoming packets will be discarded silently.
 | 
						|
 | 
						|
  @param[in]  This                  Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The EFI DHCPv4 Protocol driver is now in the Dhcp4Init phase.
 | 
						|
  @retval EFI_INVALID_PARAMETER This is NULL.
 | 
						|
  @retval EFI_ACCESS_DENIED     The EFI DHCPv4 Protocol driver is not Dhcp4InitReboot state.
 | 
						|
  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4Release (
 | 
						|
  IN EFI_DHCP4_PROTOCOL     *This
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Stops the current address configuration.
 | 
						|
 | 
						|
  The Stop() function is used to stop the DHCP configuration process. After this
 | 
						|
  function is called successfully, the EFI DHCPv4 Protocol driver is transferred
 | 
						|
  into the Dhcp4Stopped state. EFI_DHCP4_PROTOCOL.Configure() needs to be called
 | 
						|
  before DHCP configuration process can be started again. This function can be
 | 
						|
  called when the EFI DHCPv4 Protocol driver is in any state.
 | 
						|
 | 
						|
  @param[in]  This                  Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The EFI DHCPv4 Protocol driver is now in the Dhcp4Stopped phase.
 | 
						|
  @retval EFI_INVALID_PARAMETER This is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4Stop (
 | 
						|
  IN EFI_DHCP4_PROTOCOL     *This
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Builds a DHCP packet, given the options to be appended or deleted or replaced.
 | 
						|
 | 
						|
  The Build() function is used to assemble a new packet from the original packet
 | 
						|
  by replacing or deleting existing options or appending new options. This function
 | 
						|
  does not change any state of the EFI DHCPv4 Protocol driver and can be used at
 | 
						|
  any time.
 | 
						|
 | 
						|
  @param[in]  This        Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param[in]  SeedPacket  Initial packet to be used as a base for building new packet.
 | 
						|
  @param[in]  DeleteCount Number of opcodes in the DeleteList.
 | 
						|
  @param[in]  DeleteList  List of opcodes to be deleted from the seed packet.
 | 
						|
                          Ignored if DeleteCount is zero.
 | 
						|
  @param[in]  AppendCount Number of entries in the OptionList.
 | 
						|
  @param[in]  AppendList  Pointer to a DHCP option list to be appended to SeedPacket.
 | 
						|
                          If SeedPacket also contains options in this list, they are
 | 
						|
                          replaced by new options (except pad option). Ignored if
 | 
						|
                          AppendCount is zero. Type EFI_DHCP4_PACKET_OPTION
 | 
						|
  @param[out] NewPacket   Pointer to storage for the pointer to the new allocated packet.
 | 
						|
                          Use the EFI Boot Service FreePool() on the resulting pointer
 | 
						|
                          when done with the packet.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The new packet was built.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Storage for the new packet could not be allocated.
 | 
						|
  @retval EFI_INVALID_PARAMETER Some parameter is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4Build (
 | 
						|
  IN EFI_DHCP4_PROTOCOL       *This,
 | 
						|
  IN EFI_DHCP4_PACKET         *SeedPacket,
 | 
						|
  IN UINT32                   DeleteCount,
 | 
						|
  IN UINT8                    *DeleteList OPTIONAL,
 | 
						|
  IN UINT32                   AppendCount,
 | 
						|
  IN EFI_DHCP4_PACKET_OPTION  *AppendList[] OPTIONAL,
 | 
						|
  OUT EFI_DHCP4_PACKET        **NewPacket
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Transmits a DHCP formatted packet and optionally waits for responses.
 | 
						|
 | 
						|
  The TransmitReceive() function is used to transmit a DHCP packet and optionally
 | 
						|
  wait for the response from servers. This function does not change the state of
 | 
						|
  the EFI DHCPv4 Protocol driver and thus can be used at any time.
 | 
						|
 | 
						|
  @param[in]  This    Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param[in]  Token   Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The packet was successfully queued for transmission.
 | 
						|
  @retval EFI_INVALID_PARAMETER Some parameter is NULL.
 | 
						|
  @retval EFI_NOT_READY         The previous call to this function has not finished yet. Try to call
 | 
						|
                                this function after collection process completes.
 | 
						|
  @retval EFI_NO_MAPPING        The default station address is not available yet.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
 | 
						|
  @retval Others                Some other unexpected error occurred.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4TransmitReceive (
 | 
						|
  IN EFI_DHCP4_PROTOCOL                *This,
 | 
						|
  IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Parses the packed DHCP option data.
 | 
						|
 | 
						|
  The Parse() function is used to retrieve the option list from a DHCP packet.
 | 
						|
  If *OptionCount isn't zero, and there is enough space for all the DHCP options
 | 
						|
  in the Packet, each element of PacketOptionList is set to point to somewhere in
 | 
						|
  the Packet->Dhcp4.Option where a new DHCP option begins. If RFC3396 is supported,
 | 
						|
  the caller should reassemble the parsed DHCP options to get the finial result.
 | 
						|
  If *OptionCount is zero or there isn't enough space for all of them, the number
 | 
						|
  of DHCP options in the Packet is returned in OptionCount.
 | 
						|
 | 
						|
  @param  This             Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param  Packet           Pointer to packet to be parsed.
 | 
						|
  @param  OptionCount      On input, the number of entries in the PacketOptionList.
 | 
						|
                           On output, the number of entries that were written into the
 | 
						|
                           PacketOptionList.
 | 
						|
  @param  PacketOptionList List of packet option entries to be filled in. End option or pad
 | 
						|
                           options are not included.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The packet was successfully parsed.
 | 
						|
  @retval EFI_INVALID_PARAMETER Some parameter is NULL.
 | 
						|
  @retval EFI_BUFFER_TOO_SMALL  One or more of the following conditions is TRUE:
 | 
						|
                                1) *OptionCount is smaller than the number of options that
 | 
						|
                                were found in the Packet.
 | 
						|
                                2) PacketOptionList is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4Parse (
 | 
						|
  IN EFI_DHCP4_PROTOCOL       *This,
 | 
						|
  IN EFI_DHCP4_PACKET         *Packet,
 | 
						|
  IN OUT UINT32               *OptionCount,
 | 
						|
  OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL
 | 
						|
  );
 | 
						|
 | 
						|
EFI_DHCP4_PROTOCOL  mDhcp4ProtocolTemplate = {
 | 
						|
  EfiDhcp4GetModeData,
 | 
						|
  EfiDhcp4Configure,
 | 
						|
  EfiDhcp4Start,
 | 
						|
  EfiDhcp4RenewRebind,
 | 
						|
  EfiDhcp4Release,
 | 
						|
  EfiDhcp4Stop,
 | 
						|
  EfiDhcp4Build,
 | 
						|
  EfiDhcp4TransmitReceive,
 | 
						|
  EfiDhcp4Parse
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Returns the current operating mode and cached data packet for the EFI DHCPv4 Protocol driver.
 | 
						|
 | 
						|
  The GetModeData() function returns the current operating mode and cached data
 | 
						|
  packet for the EFI DHCPv4 Protocol driver.
 | 
						|
 | 
						|
  @param[in]  This          Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param[out] Dhcp4ModeData Pointer to storage for the EFI_DHCP4_MODE_DATA structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The mode data was returned.
 | 
						|
  @retval EFI_INVALID_PARAMETER This is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4GetModeData (
 | 
						|
  IN  EFI_DHCP4_PROTOCOL    *This,
 | 
						|
  OUT EFI_DHCP4_MODE_DATA   *Dhcp4ModeData
 | 
						|
  )
 | 
						|
{
 | 
						|
  DHCP_PROTOCOL             *Instance;
 | 
						|
  DHCP_SERVICE              *DhcpSb;
 | 
						|
  DHCP_PARAMETER            *Para;
 | 
						|
  EFI_TPL                   OldTpl;
 | 
						|
  IP4_ADDR                  Ip;
 | 
						|
 | 
						|
  //
 | 
						|
  // First validate the parameters.
 | 
						|
  //
 | 
						|
  if ((This == NULL) || (Dhcp4ModeData == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance = DHCP_INSTANCE_FROM_THIS (This);
 | 
						|
 | 
						|
  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
  DhcpSb  = Instance->Service;
 | 
						|
 | 
						|
  //
 | 
						|
  // Caller can use GetModeData to retrieve current DHCP states
 | 
						|
  // no matter whether it is the active child or not.
 | 
						|
  //
 | 
						|
  Dhcp4ModeData->State = (EFI_DHCP4_STATE) DhcpSb->DhcpState;
 | 
						|
  CopyMem (&Dhcp4ModeData->ConfigData, &DhcpSb->ActiveConfig, sizeof (Dhcp4ModeData->ConfigData));
 | 
						|
  CopyMem (&Dhcp4ModeData->ClientMacAddress, &DhcpSb->Mac, sizeof (Dhcp4ModeData->ClientMacAddress));
 | 
						|
 | 
						|
  Ip = HTONL (DhcpSb->ClientAddr);
 | 
						|
  CopyMem (&Dhcp4ModeData->ClientAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
 | 
						|
  Ip = HTONL (DhcpSb->Netmask);
 | 
						|
  CopyMem (&Dhcp4ModeData->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
 | 
						|
  Ip = HTONL (DhcpSb->ServerAddr);
 | 
						|
  CopyMem (&Dhcp4ModeData->ServerAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
 | 
						|
  Para = DhcpSb->Para;
 | 
						|
 | 
						|
  if (Para != NULL) {
 | 
						|
    Ip = HTONL (Para->Router);
 | 
						|
    CopyMem (&Dhcp4ModeData->RouterAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
    Dhcp4ModeData->LeaseTime = Para->Lease;
 | 
						|
  } else {
 | 
						|
    ZeroMem (&Dhcp4ModeData->RouterAddress, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
    Dhcp4ModeData->LeaseTime = 0xffffffff;
 | 
						|
  }
 | 
						|
 | 
						|
  Dhcp4ModeData->ReplyPacket = DhcpSb->Selected;
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Free the resource related to the configure parameters.
 | 
						|
  DHCP driver will make a copy of the user's configure
 | 
						|
  such as the time out value.
 | 
						|
 | 
						|
  @param  Config                 The DHCP configure data
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DhcpCleanConfigure (
 | 
						|
  IN OUT EFI_DHCP4_CONFIG_DATA  *Config
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32                    Index;
 | 
						|
 | 
						|
  if (Config->DiscoverTimeout != NULL) {
 | 
						|
    FreePool (Config->DiscoverTimeout);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Config->RequestTimeout != NULL) {
 | 
						|
    FreePool (Config->RequestTimeout);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Config->OptionList != NULL) {
 | 
						|
    for (Index = 0; Index < Config->OptionCount; Index++) {
 | 
						|
      if (Config->OptionList[Index] != NULL) {
 | 
						|
        FreePool (Config->OptionList[Index]);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool (Config->OptionList);
 | 
						|
  }
 | 
						|
 | 
						|
  ZeroMem (Config, sizeof (EFI_DHCP4_CONFIG_DATA));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Allocate memory for configure parameter such as timeout value for Dst,
 | 
						|
  then copy the configure parameter from Src to Dst.
 | 
						|
 | 
						|
  @param[out]  Dst                    The destination DHCP configure data.
 | 
						|
  @param[in]   Src                    The source DHCP configure data.
 | 
						|
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
 | 
						|
  @retval EFI_SUCCESS            The configure is copied.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
DhcpCopyConfigure (
 | 
						|
  OUT EFI_DHCP4_CONFIG_DATA  *Dst,
 | 
						|
  IN  EFI_DHCP4_CONFIG_DATA  *Src
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_DHCP4_PACKET_OPTION   **DstOptions;
 | 
						|
  EFI_DHCP4_PACKET_OPTION   **SrcOptions;
 | 
						|
  UINTN                     Len;
 | 
						|
  UINT32                    Index;
 | 
						|
 | 
						|
  CopyMem (Dst, Src, sizeof (*Dst));
 | 
						|
  Dst->DiscoverTimeout  = NULL;
 | 
						|
  Dst->RequestTimeout   = NULL;
 | 
						|
  Dst->OptionList       = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate a memory then copy DiscoverTimeout to it
 | 
						|
  //
 | 
						|
  if (Src->DiscoverTimeout != NULL) {
 | 
						|
    Len                   = Src->DiscoverTryCount * sizeof (UINT32);
 | 
						|
    Dst->DiscoverTimeout  = AllocatePool (Len);
 | 
						|
 | 
						|
    if (Dst->DiscoverTimeout == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    for (Index = 0; Index < Src->DiscoverTryCount; Index++) {
 | 
						|
      Dst->DiscoverTimeout[Index] = MAX (Src->DiscoverTimeout[Index], 1);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate a memory then copy RequestTimeout to it
 | 
						|
  //
 | 
						|
  if (Src->RequestTimeout != NULL) {
 | 
						|
    Len                 = Src->RequestTryCount * sizeof (UINT32);
 | 
						|
    Dst->RequestTimeout = AllocatePool (Len);
 | 
						|
 | 
						|
    if (Dst->RequestTimeout == NULL) {
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    for (Index = 0; Index < Src->RequestTryCount; Index++) {
 | 
						|
      Dst->RequestTimeout[Index] = MAX (Src->RequestTimeout[Index], 1);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate an array of dhcp option point, then allocate memory
 | 
						|
  // for each option and copy the source option to it
 | 
						|
  //
 | 
						|
  if (Src->OptionList != NULL) {
 | 
						|
    Len             = Src->OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *);
 | 
						|
    Dst->OptionList = AllocateZeroPool (Len);
 | 
						|
 | 
						|
    if (Dst->OptionList == NULL) {
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    DstOptions  = Dst->OptionList;
 | 
						|
    SrcOptions  = Src->OptionList;
 | 
						|
 | 
						|
    for (Index = 0; Index < Src->OptionCount; Index++) {
 | 
						|
      Len = sizeof (EFI_DHCP4_PACKET_OPTION) + MAX (SrcOptions[Index]->Length - 1, 0);
 | 
						|
 | 
						|
      DstOptions[Index] = AllocatePool (Len);
 | 
						|
 | 
						|
      if (DstOptions[Index] == NULL) {
 | 
						|
        goto ON_ERROR;
 | 
						|
      }
 | 
						|
 | 
						|
      CopyMem (DstOptions[Index], SrcOptions[Index], Len);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
  DhcpCleanConfigure (Dst);
 | 
						|
  return EFI_OUT_OF_RESOURCES;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Give up the control of the DHCP service to let other child
 | 
						|
  resume. Don't change the service's DHCP state and the Client
 | 
						|
  address and option list configure as required by RFC2131.
 | 
						|
 | 
						|
  @param  DhcpSb                 The DHCP service instance.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DhcpYieldControl (
 | 
						|
  IN DHCP_SERVICE           *DhcpSb
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_DHCP4_CONFIG_DATA     *Config;
 | 
						|
 | 
						|
  Config    = &DhcpSb->ActiveConfig;
 | 
						|
 | 
						|
  DhcpSb->ServiceState  = DHCP_UNCONFIGED;
 | 
						|
  DhcpSb->ActiveChild   = NULL;
 | 
						|
 | 
						|
  if (Config->DiscoverTimeout != NULL) {
 | 
						|
    FreePool (Config->DiscoverTimeout);
 | 
						|
 | 
						|
    Config->DiscoverTryCount  = 0;
 | 
						|
    Config->DiscoverTimeout   = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Config->RequestTimeout != NULL) {
 | 
						|
    FreePool (Config->RequestTimeout);
 | 
						|
 | 
						|
    Config->RequestTryCount = 0;
 | 
						|
    Config->RequestTimeout  = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  Config->Dhcp4Callback   = NULL;
 | 
						|
  Config->CallbackContext = NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Initializes, changes, or resets the operational settings for the EFI DHCPv4 Protocol driver.
 | 
						|
 | 
						|
  The Configure() function is used to initialize, change, or reset the operational
 | 
						|
  settings of the EFI DHCPv4 Protocol driver for the communication device on which
 | 
						|
  the EFI DHCPv4 Service Binding Protocol is installed. This function can be
 | 
						|
  successfully called only if both of the following are true:
 | 
						|
  * This instance of the EFI DHCPv4 Protocol driver is in the Dhcp4Stopped, Dhcp4Init,
 | 
						|
    Dhcp4InitReboot, or Dhcp4Bound states.
 | 
						|
  * No other EFI DHCPv4 Protocol driver instance that is controlled by this EFI
 | 
						|
    DHCPv4 Service Binding Protocol driver instance has configured this EFI DHCPv4
 | 
						|
    Protocol driver.
 | 
						|
  When this driver is in the Dhcp4Stopped state, it can transfer into one of the
 | 
						|
  following two possible initial states:
 | 
						|
  * Dhcp4Init
 | 
						|
  * Dhcp4InitReboot
 | 
						|
  The driver can transfer into these states by calling Configure() with a non-NULL
 | 
						|
  Dhcp4CfgData. The driver will transfer into the appropriate state based on the
 | 
						|
  supplied client network address in the ClientAddress parameter and DHCP options
 | 
						|
  in the OptionList parameter as described in RFC 2131.
 | 
						|
  When Configure() is called successfully while Dhcp4CfgData is set to NULL, the
 | 
						|
  default configuring data will be reset in the EFI DHCPv4 Protocol driver and
 | 
						|
  the state of the EFI DHCPv4 Protocol driver will not be changed. If one instance
 | 
						|
  wants to make it possible for another instance to configure the EFI DHCPv4 Protocol
 | 
						|
  driver, it must call this function with Dhcp4CfgData set to NULL.
 | 
						|
 | 
						|
  @param[in]  This                   Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param[in]  Dhcp4CfgData           Pointer to the EFI_DHCP4_CONFIG_DATA.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The EFI DHCPv4 Protocol driver is now in the Dhcp4Init or
 | 
						|
                                Dhcp4InitReboot state, if the original state of this driver
 | 
						|
                                was Dhcp4Stopped and the value of Dhcp4CfgData was
 | 
						|
                                not NULL. Otherwise, the state was left unchanged.
 | 
						|
  @retval EFI_ACCESS_DENIED     This instance of the EFI DHCPv4 Protocol driver was not in the
 | 
						|
                                Dhcp4Stopped, Dhcp4Init, Dhcp4InitReboot, or Dhcp4Bound state;
 | 
						|
                                Or onother instance of this EFI DHCPv4 Protocol driver is already
 | 
						|
                                in a valid configured state.
 | 
						|
  @retval EFI_INVALID_PARAMETER Some parameter is NULL.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
 | 
						|
  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4Configure (
 | 
						|
  IN EFI_DHCP4_PROTOCOL     *This,
 | 
						|
  IN EFI_DHCP4_CONFIG_DATA  *Dhcp4CfgData       OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_DHCP4_CONFIG_DATA     *Config;
 | 
						|
  DHCP_PROTOCOL             *Instance;
 | 
						|
  DHCP_SERVICE              *DhcpSb;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_TPL                   OldTpl;
 | 
						|
  UINT32                    Index;
 | 
						|
  IP4_ADDR                  Ip;
 | 
						|
 | 
						|
  //
 | 
						|
  // First validate the parameters
 | 
						|
  //
 | 
						|
  if (This == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Dhcp4CfgData != NULL) {
 | 
						|
    if ((Dhcp4CfgData->DiscoverTryCount != 0) && (Dhcp4CfgData->DiscoverTimeout == NULL)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((Dhcp4CfgData->RequestTryCount != 0) && (Dhcp4CfgData->RequestTimeout == NULL)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((Dhcp4CfgData->OptionCount != 0) && (Dhcp4CfgData->OptionList == NULL)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    CopyMem (&Ip, &Dhcp4CfgData->ClientAddress, sizeof (IP4_ADDR));
 | 
						|
 | 
						|
    if ((Ip != 0) && !NetIp4IsUnicast (NTOHL (Ip), 0)) {
 | 
						|
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Instance = DHCP_INSTANCE_FROM_THIS (This);
 | 
						|
 | 
						|
  if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
 | 
						|
  DhcpSb  = Instance->Service;
 | 
						|
  Config  = &DhcpSb->ActiveConfig;
 | 
						|
 | 
						|
  Status  = EFI_ACCESS_DENIED;
 | 
						|
 | 
						|
  if ((DhcpSb->DhcpState != Dhcp4Stopped) &&
 | 
						|
      (DhcpSb->DhcpState != Dhcp4Init) &&
 | 
						|
      (DhcpSb->DhcpState != Dhcp4InitReboot) &&
 | 
						|
      (DhcpSb->DhcpState != Dhcp4Bound)) {
 | 
						|
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((DhcpSb->ActiveChild != NULL) && (DhcpSb->ActiveChild != Instance)) {
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Dhcp4CfgData != NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    DhcpCleanConfigure (Config);
 | 
						|
 | 
						|
    if (EFI_ERROR (DhcpCopyConfigure (Config, Dhcp4CfgData))) {
 | 
						|
      goto ON_EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    DhcpSb->UserOptionLen = 0;
 | 
						|
 | 
						|
    for (Index = 0; Index < Dhcp4CfgData->OptionCount; Index++) {
 | 
						|
      DhcpSb->UserOptionLen += Dhcp4CfgData->OptionList[Index]->Length + 2;
 | 
						|
    }
 | 
						|
 | 
						|
    DhcpSb->ActiveChild = Instance;
 | 
						|
 | 
						|
    if (DhcpSb->DhcpState == Dhcp4Stopped) {
 | 
						|
      DhcpSb->ClientAddr = EFI_NTOHL (Dhcp4CfgData->ClientAddress);
 | 
						|
 | 
						|
      if (DhcpSb->ClientAddr != 0) {
 | 
						|
        DhcpSb->DhcpState = Dhcp4InitReboot;
 | 
						|
      } else {
 | 
						|
        DhcpSb->DhcpState = Dhcp4Init;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    DhcpSb->ServiceState  = DHCP_CONFIGED;
 | 
						|
    Status                = EFI_SUCCESS;
 | 
						|
 | 
						|
  } else if (DhcpSb->ActiveChild == Instance) {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
    DhcpYieldControl (DhcpSb);
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Starts the DHCP configuration process.
 | 
						|
 | 
						|
  The Start() function starts the DHCP configuration process. This function can
 | 
						|
  be called only when the EFI DHCPv4 Protocol driver is in the Dhcp4Init or
 | 
						|
  Dhcp4InitReboot state.
 | 
						|
  If the DHCP process completes successfully, the state of the EFI DHCPv4 Protocol
 | 
						|
  driver will be transferred through Dhcp4Selecting and Dhcp4Requesting to the
 | 
						|
  Dhcp4Bound state. The CompletionEvent will then be signaled if it is not NULL.
 | 
						|
  If the process aborts, either by the user or by some unexpected network error,
 | 
						|
  the state is restored to the Dhcp4Init state. The Start() function can be called
 | 
						|
  again to restart the process.
 | 
						|
  Refer to RFC 2131 for precise state transitions during this process. At the
 | 
						|
  time when each event occurs in this process, the callback function that was set
 | 
						|
  by EFI_DHCP4_PROTOCOL.Configure() will be called and the user can take this
 | 
						|
  opportunity to control the process.
 | 
						|
 | 
						|
  @param[in]  This            Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param[in]  CompletionEvent If not NULL, indicates the event that will be signaled when the
 | 
						|
                              EFI DHCPv4 Protocol driver is transferred into the
 | 
						|
                              Dhcp4Bound state or when the DHCP process is aborted.
 | 
						|
                              EFI_DHCP4_PROTOCOL.GetModeData() can be called to
 | 
						|
                              check the completion status. If NULL,
 | 
						|
                              EFI_DHCP4_PROTOCOL.Start() will wait until the driver
 | 
						|
                              is transferred into the Dhcp4Bound state or the process fails.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The DHCP configuration process has started, or it has completed
 | 
						|
                                when CompletionEvent is NULL.
 | 
						|
  @retval EFI_NOT_STARTED       The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped
 | 
						|
                                state. EFI_DHCP4_PROTOCOL. Configure() needs to be called.
 | 
						|
  @retval EFI_INVALID_PARAMETER This is NULL.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
 | 
						|
  @retval EFI_TIMEOUT           The DHCP configuration process failed because no response was
 | 
						|
                                received from the server within the specified timeout value.
 | 
						|
  @retval EFI_ABORTED           The user aborted the DHCP process.
 | 
						|
  @retval EFI_ALREADY_STARTED   Some other EFI DHCPv4 Protocol instance already started the
 | 
						|
                                DHCP process.
 | 
						|
  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
 | 
						|
  @retval EFI_NO_MEDIA          There was a media error.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4Start (
 | 
						|
  IN EFI_DHCP4_PROTOCOL     *This,
 | 
						|
  IN EFI_EVENT              CompletionEvent   OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  DHCP_PROTOCOL             *Instance;
 | 
						|
  DHCP_SERVICE              *DhcpSb;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_TPL                   OldTpl;
 | 
						|
 | 
						|
  //
 | 
						|
  // First validate the parameters
 | 
						|
  //
 | 
						|
  if (This == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance = DHCP_INSTANCE_FROM_THIS (This);
 | 
						|
 | 
						|
  if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
  DhcpSb  = Instance->Service;
 | 
						|
 | 
						|
  if (DhcpSb->DhcpState == Dhcp4Stopped) {
 | 
						|
    Status = EFI_NOT_STARTED;
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((DhcpSb->DhcpState != Dhcp4Init) && (DhcpSb->DhcpState != Dhcp4InitReboot)) {
 | 
						|
    Status = EFI_ALREADY_STARTED;
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  DhcpSb->IoStatus = EFI_ALREADY_STARTED;
 | 
						|
 | 
						|
  if (EFI_ERROR (Status = DhcpInitRequest (DhcpSb))) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  Instance->CompletionEvent = CompletionEvent;
 | 
						|
 | 
						|
  //
 | 
						|
  // Restore the TPL now, don't call poll function at TPL_CALLBACK.
 | 
						|
  //
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  if (CompletionEvent == NULL) {
 | 
						|
    while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {
 | 
						|
      DhcpSb->UdpIo->Protocol.Udp4->Poll (DhcpSb->UdpIo->Protocol.Udp4);
 | 
						|
    }
 | 
						|
 | 
						|
    return DhcpSb->IoStatus;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Extends the lease time by sending a request packet.
 | 
						|
 | 
						|
  The RenewRebind() function is used to manually extend the lease time when the
 | 
						|
  EFI DHCPv4 Protocol driver is in the Dhcp4Bound state and the lease time has
 | 
						|
  not expired yet. This function will send a request packet to the previously
 | 
						|
  found server (or to any server when RebindRequest is TRUE) and transfer the
 | 
						|
  state into the Dhcp4Renewing state (or Dhcp4Rebinding when RebindingRequest is
 | 
						|
  TRUE). When a response is received, the state is returned to Dhcp4Bound.
 | 
						|
  If no response is received before the try count is exceeded (the RequestTryCount
 | 
						|
  field that is specified in EFI_DHCP4_CONFIG_DATA) but before the lease time that
 | 
						|
  was issued by the previous server expires, the driver will return to the Dhcp4Bound
 | 
						|
  state and the previous configuration is restored. The outgoing and incoming packets
 | 
						|
  can be captured by the EFI_DHCP4_CALLBACK function.
 | 
						|
 | 
						|
  @param[in]  This            Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param[in]  RebindRequest   If TRUE, this function broadcasts the request packets and enters
 | 
						|
                              the Dhcp4Rebinding state. Otherwise, it sends a unicast
 | 
						|
                              request packet and enters the Dhcp4Renewing state.
 | 
						|
  @param[in]  CompletionEvent If not NULL, this event is signaled when the renew/rebind phase
 | 
						|
                              completes or some error occurs.
 | 
						|
                              EFI_DHCP4_PROTOCOL.GetModeData() can be called to
 | 
						|
                              check the completion status. If NULL,
 | 
						|
                              EFI_DHCP4_PROTOCOL.RenewRebind() will busy-wait
 | 
						|
                              until the DHCP process finishes.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The EFI DHCPv4 Protocol driver is now in the
 | 
						|
                                Dhcp4Renewing state or is back to the Dhcp4Bound state.
 | 
						|
  @retval EFI_NOT_STARTED       The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped
 | 
						|
                                state. EFI_DHCP4_PROTOCOL.Configure() needs to
 | 
						|
                                be called.
 | 
						|
  @retval EFI_INVALID_PARAMETER This is NULL.
 | 
						|
  @retval EFI_TIMEOUT           There was no response from the server when the try count was
 | 
						|
                                exceeded.
 | 
						|
  @retval EFI_ACCESS_DENIED     The driver is not in the Dhcp4Bound state.
 | 
						|
  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4RenewRebind (
 | 
						|
  IN EFI_DHCP4_PROTOCOL     *This,
 | 
						|
  IN BOOLEAN                RebindRequest,
 | 
						|
  IN EFI_EVENT              CompletionEvent   OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  DHCP_PROTOCOL             *Instance;
 | 
						|
  DHCP_SERVICE              *DhcpSb;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_TPL                   OldTpl;
 | 
						|
 | 
						|
  //
 | 
						|
  // First validate the parameters
 | 
						|
  //
 | 
						|
  if (This == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance = DHCP_INSTANCE_FROM_THIS (This);
 | 
						|
 | 
						|
  if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
  DhcpSb  = Instance->Service;
 | 
						|
 | 
						|
  if (DhcpSb->DhcpState == Dhcp4Stopped) {
 | 
						|
    Status = EFI_NOT_STARTED;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  if (DhcpSb->DhcpState != Dhcp4Bound) {
 | 
						|
    Status = EFI_ACCESS_DENIED;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  if (DHCP_IS_BOOTP (DhcpSb->Para)) {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Transit the states then send a extra DHCP request
 | 
						|
  //
 | 
						|
  if (!RebindRequest) {
 | 
						|
    DhcpSetState (DhcpSb, Dhcp4Renewing, FALSE);
 | 
						|
  } else {
 | 
						|
    DhcpSetState (DhcpSb, Dhcp4Rebinding, FALSE);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Clear initial time to make sure that elapsed-time
 | 
						|
  // is set to 0 for first REQUEST in renewal process.
 | 
						|
  //
 | 
						|
  Instance->ElaspedTime = 0;
 | 
						|
 | 
						|
  Status = DhcpSendMessage (
 | 
						|
             DhcpSb,
 | 
						|
             DhcpSb->Selected,
 | 
						|
             DhcpSb->Para,
 | 
						|
             DHCP_MSG_REQUEST,
 | 
						|
             (UINT8 *) "Extra renew/rebind by the application"
 | 
						|
             );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DhcpSetState (DhcpSb, Dhcp4Bound, FALSE);
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  DhcpSb->ExtraRefresh        = TRUE;
 | 
						|
  DhcpSb->IoStatus            = EFI_ALREADY_STARTED;
 | 
						|
  Instance->RenewRebindEvent  = CompletionEvent;
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  if (CompletionEvent == NULL) {
 | 
						|
    while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {
 | 
						|
      DhcpSb->UdpIo->Protocol.Udp4->Poll (DhcpSb->UdpIo->Protocol.Udp4);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    return DhcpSb->IoStatus;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Releases the current address configuration.
 | 
						|
 | 
						|
  The Release() function releases the current configured IP address by doing either
 | 
						|
  of the following:
 | 
						|
  * Sending a DHCPRELEASE packet when the EFI DHCPv4 Protocol driver is in the
 | 
						|
    Dhcp4Bound state
 | 
						|
  * Setting the previously assigned IP address that was provided with the
 | 
						|
    EFI_DHCP4_PROTOCOL.Configure() function to 0.0.0.0 when the driver is in
 | 
						|
    Dhcp4InitReboot state
 | 
						|
  After a successful call to this function, the EFI DHCPv4 Protocol driver returns
 | 
						|
  to the Dhcp4Init state and any subsequent incoming packets will be discarded silently.
 | 
						|
 | 
						|
  @param[in]  This                  Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The EFI DHCPv4 Protocol driver is now in the Dhcp4Init phase.
 | 
						|
  @retval EFI_INVALID_PARAMETER This is NULL.
 | 
						|
  @retval EFI_ACCESS_DENIED     The EFI DHCPv4 Protocol driver is not Dhcp4InitReboot state.
 | 
						|
  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4Release (
 | 
						|
  IN EFI_DHCP4_PROTOCOL     *This
 | 
						|
  )
 | 
						|
{
 | 
						|
  DHCP_PROTOCOL             *Instance;
 | 
						|
  DHCP_SERVICE              *DhcpSb;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_TPL                   OldTpl;
 | 
						|
 | 
						|
  //
 | 
						|
  // First validate the parameters
 | 
						|
  //
 | 
						|
  if (This == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance = DHCP_INSTANCE_FROM_THIS (This);
 | 
						|
 | 
						|
  if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Status  = EFI_SUCCESS;
 | 
						|
  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
  DhcpSb  = Instance->Service;
 | 
						|
 | 
						|
  if ((DhcpSb->DhcpState != Dhcp4InitReboot) && (DhcpSb->DhcpState != Dhcp4Bound)) {
 | 
						|
    Status = EFI_ACCESS_DENIED;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!DHCP_IS_BOOTP (DhcpSb->Para) && (DhcpSb->DhcpState == Dhcp4Bound)) {
 | 
						|
    Status = DhcpSendMessage (
 | 
						|
               DhcpSb,
 | 
						|
               DhcpSb->Selected,
 | 
						|
               DhcpSb->Para,
 | 
						|
               DHCP_MSG_RELEASE,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
      goto ON_EXIT;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DhcpCleanLease (DhcpSb);
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Stops the current address configuration.
 | 
						|
 | 
						|
  The Stop() function is used to stop the DHCP configuration process. After this
 | 
						|
  function is called successfully, the EFI DHCPv4 Protocol driver is transferred
 | 
						|
  into the Dhcp4Stopped state. EFI_DHCP4_PROTOCOL.Configure() needs to be called
 | 
						|
  before DHCP configuration process can be started again. This function can be
 | 
						|
  called when the EFI DHCPv4 Protocol driver is in any state.
 | 
						|
 | 
						|
  @param[in]  This                  Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The EFI DHCPv4 Protocol driver is now in the Dhcp4Stopped phase.
 | 
						|
  @retval EFI_INVALID_PARAMETER This is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4Stop (
 | 
						|
  IN EFI_DHCP4_PROTOCOL     *This
 | 
						|
  )
 | 
						|
{
 | 
						|
  DHCP_PROTOCOL             *Instance;
 | 
						|
  DHCP_SERVICE              *DhcpSb;
 | 
						|
  EFI_TPL                   OldTpl;
 | 
						|
 | 
						|
  //
 | 
						|
  // First validate the parameters
 | 
						|
  //
 | 
						|
  if (This == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance = DHCP_INSTANCE_FROM_THIS (This);
 | 
						|
 | 
						|
  if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
  DhcpSb  = Instance->Service;
 | 
						|
 | 
						|
  DhcpCleanLease (DhcpSb);
 | 
						|
 | 
						|
  DhcpSb->DhcpState     = Dhcp4Stopped;
 | 
						|
  DhcpSb->ServiceState  = DHCP_UNCONFIGED;
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Builds a DHCP packet, given the options to be appended or deleted or replaced.
 | 
						|
 | 
						|
  The Build() function is used to assemble a new packet from the original packet
 | 
						|
  by replacing or deleting existing options or appending new options. This function
 | 
						|
  does not change any state of the EFI DHCPv4 Protocol driver and can be used at
 | 
						|
  any time.
 | 
						|
 | 
						|
  @param[in]  This        Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param[in]  SeedPacket  Initial packet to be used as a base for building new packet.
 | 
						|
  @param[in]  DeleteCount Number of opcodes in the DeleteList.
 | 
						|
  @param[in]  DeleteList  List of opcodes to be deleted from the seed packet.
 | 
						|
                          Ignored if DeleteCount is zero.
 | 
						|
  @param[in]  AppendCount Number of entries in the OptionList.
 | 
						|
  @param[in]  AppendList  Pointer to a DHCP option list to be appended to SeedPacket.
 | 
						|
                          If SeedPacket also contains options in this list, they are
 | 
						|
                          replaced by new options (except pad option). Ignored if
 | 
						|
                          AppendCount is zero. Type EFI_DHCP4_PACKET_OPTION
 | 
						|
  @param[out] NewPacket   Pointer to storage for the pointer to the new allocated packet.
 | 
						|
                          Use the EFI Boot Service FreePool() on the resulting pointer
 | 
						|
                          when done with the packet.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The new packet was built.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Storage for the new packet could not be allocated.
 | 
						|
  @retval EFI_INVALID_PARAMETER Some parameter is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4Build (
 | 
						|
  IN EFI_DHCP4_PROTOCOL       *This,
 | 
						|
  IN EFI_DHCP4_PACKET         *SeedPacket,
 | 
						|
  IN UINT32                   DeleteCount,
 | 
						|
  IN UINT8                    *DeleteList OPTIONAL,
 | 
						|
  IN UINT32                   AppendCount,
 | 
						|
  IN EFI_DHCP4_PACKET_OPTION  *AppendList[] OPTIONAL,
 | 
						|
  OUT EFI_DHCP4_PACKET        **NewPacket
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // First validate the parameters
 | 
						|
  //
 | 
						|
  if ((This == NULL) || (NewPacket == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((SeedPacket == NULL) || (SeedPacket->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||
 | 
						|
      EFI_ERROR (DhcpValidateOptions (SeedPacket, NULL))) {
 | 
						|
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (((DeleteCount == 0) && (AppendCount == 0)) ||
 | 
						|
      ((DeleteCount != 0) && (DeleteList == NULL)) ||
 | 
						|
      ((AppendCount != 0) && (AppendList == NULL))) {
 | 
						|
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  return DhcpBuild (
 | 
						|
           SeedPacket,
 | 
						|
           DeleteCount,
 | 
						|
           DeleteList,
 | 
						|
           AppendCount,
 | 
						|
           AppendList,
 | 
						|
           NewPacket
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Callback by UdpIoCreatePort() when creating UdpIo for this Dhcp4 instance.
 | 
						|
 | 
						|
  @param[in] UdpIo      The UdpIo being created.
 | 
						|
  @param[in] Context    Dhcp4 instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   UdpIo is configured successfully.
 | 
						|
  @retval other         Other error occurs.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
Dhcp4InstanceConfigUdpIo (
 | 
						|
  IN UDP_IO       *UdpIo,
 | 
						|
  IN VOID         *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  DHCP_PROTOCOL                     *Instance;
 | 
						|
  DHCP_SERVICE                      *DhcpSb;
 | 
						|
  EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token;
 | 
						|
  EFI_UDP4_CONFIG_DATA              UdpConfigData;
 | 
						|
  IP4_ADDR                          Ip;
 | 
						|
 | 
						|
  Instance = (DHCP_PROTOCOL *) Context;
 | 
						|
  DhcpSb   = Instance->Service;
 | 
						|
  Token    = Instance->Token;
 | 
						|
 | 
						|
  ZeroMem (&UdpConfigData, sizeof (EFI_UDP4_CONFIG_DATA));
 | 
						|
 | 
						|
  UdpConfigData.AcceptBroadcast    = TRUE;
 | 
						|
  UdpConfigData.AllowDuplicatePort = TRUE;
 | 
						|
  UdpConfigData.TimeToLive         = 64;
 | 
						|
  UdpConfigData.DoNotFragment      = TRUE;
 | 
						|
 | 
						|
  Ip = HTONL (DhcpSb->ClientAddr);
 | 
						|
  CopyMem (&UdpConfigData.StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
 | 
						|
  Ip = HTONL (DhcpSb->Netmask);
 | 
						|
  CopyMem (&UdpConfigData.SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
 | 
						|
  if ((Token->ListenPointCount == 0) || (Token->ListenPoints[0].ListenPort == 0)) {
 | 
						|
    UdpConfigData.StationPort = DHCP_CLIENT_PORT;
 | 
						|
  } else {
 | 
						|
    UdpConfigData.StationPort = Token->ListenPoints[0].ListenPort;
 | 
						|
  }
 | 
						|
 | 
						|
  return UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfigData);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create UdpIo for this Dhcp4 instance.
 | 
						|
 | 
						|
  @param Instance   The Dhcp4 instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS                UdpIo is created successfully.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES       Fails to create UdpIo because of limited
 | 
						|
                                     resources or configuration failure.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Dhcp4InstanceCreateUdpIo (
 | 
						|
  IN OUT DHCP_PROTOCOL  *Instance
 | 
						|
  )
 | 
						|
{
 | 
						|
  DHCP_SERVICE  *DhcpSb;
 | 
						|
  EFI_STATUS    Status;
 | 
						|
  VOID          *Udp4;
 | 
						|
 | 
						|
  ASSERT (Instance->Token != NULL);
 | 
						|
 | 
						|
  DhcpSb          = Instance->Service;
 | 
						|
  Instance->UdpIo = UdpIoCreateIo (
 | 
						|
                      DhcpSb->Controller,
 | 
						|
                      DhcpSb->Image,
 | 
						|
                      Dhcp4InstanceConfigUdpIo,
 | 
						|
                      UDP_IO_UDP4_VERSION,
 | 
						|
                      Instance
 | 
						|
                      );
 | 
						|
  if (Instance->UdpIo == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  } else {
 | 
						|
    Status = gBS->OpenProtocol (
 | 
						|
                    Instance->UdpIo->UdpHandle,
 | 
						|
                    &gEfiUdp4ProtocolGuid,
 | 
						|
                    (VOID **) &Udp4,
 | 
						|
                    Instance->Service->Image,
 | 
						|
                    Instance->Handle,
 | 
						|
                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      UdpIoFreeIo (Instance->UdpIo);
 | 
						|
      Instance->UdpIo = NULL;
 | 
						|
    }
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Callback of Dhcp packet. Does nothing.
 | 
						|
 | 
						|
  @param Arg           The context.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
DhcpDummyExtFree (
 | 
						|
  IN VOID                   *Arg
 | 
						|
  )
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Callback of UdpIoRecvDatagram() that handles a Dhcp4 packet.
 | 
						|
 | 
						|
  Only BOOTP responses will be handled that correspond to the Xid of the request
 | 
						|
  sent out. The packet will be queued to the response queue.
 | 
						|
 | 
						|
  @param UdpPacket        The Dhcp4 packet.
 | 
						|
  @param EndPoint         Udp4 address pair.
 | 
						|
  @param IoStatus         Status of the input.
 | 
						|
  @param Context          Extra info for the input.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
PxeDhcpInput (
 | 
						|
  NET_BUF                   *UdpPacket,
 | 
						|
  UDP_END_POINT             *EndPoint,
 | 
						|
  EFI_STATUS                IoStatus,
 | 
						|
  VOID                      *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  DHCP_PROTOCOL                     *Instance;
 | 
						|
  DHCP_SERVICE                      *DhcpSb;
 | 
						|
  EFI_DHCP4_HEADER                  *Head;
 | 
						|
  NET_BUF                           *Wrap;
 | 
						|
  EFI_DHCP4_PACKET                  *Packet;
 | 
						|
  EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token;
 | 
						|
  UINT32                            Len;
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
 | 
						|
  Wrap     = NULL;
 | 
						|
  Instance = (DHCP_PROTOCOL *) Context;
 | 
						|
  Token    = Instance->Token;
 | 
						|
  DhcpSb   = Instance->Service;
 | 
						|
 | 
						|
  //
 | 
						|
  // Don't restart receive if error occurs or DHCP is destroyed.
 | 
						|
  //
 | 
						|
  if (EFI_ERROR (IoStatus)) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  ASSERT (UdpPacket != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate the packet received
 | 
						|
  //
 | 
						|
  if (UdpPacket->TotalSize < sizeof (EFI_DHCP4_HEADER)) {
 | 
						|
    goto RESTART;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy the DHCP message to a continuous memory block, make the buffer size
 | 
						|
  // of the EFI_DHCP4_PACKET a multiple of 4-byte.
 | 
						|
  //
 | 
						|
  Len  = NET_ROUNDUP (sizeof (EFI_DHCP4_PACKET) + UdpPacket->TotalSize - sizeof (EFI_DHCP4_HEADER), 4);
 | 
						|
  Wrap = NetbufAlloc (Len);
 | 
						|
  if (Wrap == NULL) {
 | 
						|
    goto RESTART;
 | 
						|
  }
 | 
						|
 | 
						|
  Packet         = (EFI_DHCP4_PACKET *) NetbufAllocSpace (Wrap, Len, NET_BUF_TAIL);
 | 
						|
  ASSERT (Packet != NULL);
 | 
						|
 | 
						|
  Packet->Size   = Len;
 | 
						|
  Head           = &Packet->Dhcp4.Header;
 | 
						|
  Packet->Length = NetbufCopy (UdpPacket, 0, UdpPacket->TotalSize, (UINT8 *) Head);
 | 
						|
 | 
						|
  if (Packet->Length != UdpPacket->TotalSize) {
 | 
						|
    goto RESTART;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Is this packet the answer to our packet?
 | 
						|
  //
 | 
						|
  if ((Head->OpCode != BOOTP_REPLY) ||
 | 
						|
      (Head->Xid != Token->Packet->Dhcp4.Header.Xid) ||
 | 
						|
      (CompareMem (DhcpSb->ClientAddressSendOut, Head->ClientHwAddr, Head->HwAddrLen) != 0)) {
 | 
						|
    goto RESTART;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate the options and retrieve the interested options
 | 
						|
  //
 | 
						|
  if ((Packet->Length > sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32)) &&
 | 
						|
      (Packet->Dhcp4.Magik == DHCP_OPTION_MAGIC) &&
 | 
						|
      EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {
 | 
						|
 | 
						|
    goto RESTART;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Keep this packet in the ResponseQueue.
 | 
						|
  //
 | 
						|
  NET_GET_REF (Wrap);
 | 
						|
  NetbufQueAppend (&Instance->ResponseQueue, Wrap);
 | 
						|
 | 
						|
RESTART:
 | 
						|
 | 
						|
  NetbufFree (UdpPacket);
 | 
						|
 | 
						|
  if (Wrap != NULL) {
 | 
						|
    NetbufFree (Wrap);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    PxeDhcpDone (Instance);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Complete a Dhcp4 transaction and signal the upper layer.
 | 
						|
 | 
						|
  @param Instance      Dhcp4 instance.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
PxeDhcpDone (
 | 
						|
  IN DHCP_PROTOCOL  *Instance
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token;
 | 
						|
 | 
						|
  Token = Instance->Token;
 | 
						|
 | 
						|
  Token->ResponseCount = Instance->ResponseQueue.BufNum;
 | 
						|
  if (Token->ResponseCount != 0) {
 | 
						|
    Token->ResponseList = (EFI_DHCP4_PACKET *) AllocatePool (Instance->ResponseQueue.BufSize);
 | 
						|
    if (Token->ResponseList == NULL) {
 | 
						|
      Token->Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto SIGNAL_USER;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Copy the received DHCP responses.
 | 
						|
    //
 | 
						|
    NetbufQueCopy (&Instance->ResponseQueue, 0, Instance->ResponseQueue.BufSize, (UINT8 *) Token->ResponseList);
 | 
						|
    Token->Status = EFI_SUCCESS;
 | 
						|
  } else {
 | 
						|
    Token->ResponseList = NULL;
 | 
						|
    Token->Status       = EFI_TIMEOUT;
 | 
						|
  }
 | 
						|
 | 
						|
SIGNAL_USER:
 | 
						|
  //
 | 
						|
  // Clean up the resources dedicated for this transmit receive transaction.
 | 
						|
  //
 | 
						|
  NetbufQueFlush (&Instance->ResponseQueue);
 | 
						|
  UdpIoCleanIo (Instance->UdpIo);
 | 
						|
  gBS->CloseProtocol (
 | 
						|
         Instance->UdpIo->UdpHandle,
 | 
						|
         &gEfiUdp4ProtocolGuid,
 | 
						|
         Instance->Service->Image,
 | 
						|
         Instance->Handle
 | 
						|
         );
 | 
						|
  UdpIoFreeIo (Instance->UdpIo);
 | 
						|
  Instance->UdpIo = NULL;
 | 
						|
  Instance->Token = NULL;
 | 
						|
 | 
						|
  if (Token->CompletionEvent != NULL) {
 | 
						|
    gBS->SignalEvent (Token->CompletionEvent);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Transmits a DHCP formatted packet and optionally waits for responses.
 | 
						|
 | 
						|
  The TransmitReceive() function is used to transmit a DHCP packet and optionally
 | 
						|
  wait for the response from servers. This function does not change the state of
 | 
						|
  the EFI DHCPv4 Protocol driver and thus can be used at any time.
 | 
						|
 | 
						|
  @param[in]  This    Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param[in]  Token   Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The packet was successfully queued for transmission.
 | 
						|
  @retval EFI_INVALID_PARAMETER Some parameter is NULL.
 | 
						|
  @retval EFI_NOT_READY         The previous call to this function has not finished yet. Try to call
 | 
						|
                                this function after collection process completes.
 | 
						|
  @retval EFI_NO_MAPPING        The default station address is not available yet.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
 | 
						|
  @retval Others                Some other unexpected error occurred.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4TransmitReceive (
 | 
						|
  IN EFI_DHCP4_PROTOCOL                *This,
 | 
						|
  IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token
 | 
						|
  )
 | 
						|
{
 | 
						|
  DHCP_PROTOCOL  *Instance;
 | 
						|
  EFI_TPL        OldTpl;
 | 
						|
  EFI_STATUS     Status;
 | 
						|
  NET_FRAGMENT   Frag;
 | 
						|
  NET_BUF        *Wrap;
 | 
						|
  UDP_END_POINT  EndPoint;
 | 
						|
  IP4_ADDR       Ip;
 | 
						|
  DHCP_SERVICE   *DhcpSb;
 | 
						|
  EFI_IP_ADDRESS Gateway;
 | 
						|
  IP4_ADDR       SubnetMask;
 | 
						|
 | 
						|
  if ((This == NULL) || (Token == NULL) || (Token->Packet == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance = DHCP_INSTANCE_FROM_THIS (This);
 | 
						|
  DhcpSb   = Instance->Service;
 | 
						|
 | 
						|
  if (Instance->Token != NULL) {
 | 
						|
    //
 | 
						|
    // The previous call to TransmitReceive is not finished.
 | 
						|
    //
 | 
						|
    return EFI_NOT_READY;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Token->Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC)                   ||
 | 
						|
      (NTOHL (Token->Packet->Dhcp4.Header.Xid) == Instance->Service->Xid) ||
 | 
						|
      (Token->TimeoutValue == 0)                                          ||
 | 
						|
      ((Token->ListenPointCount != 0) && (Token->ListenPoints == NULL))   ||
 | 
						|
      EFI_ERROR (DhcpValidateOptions (Token->Packet, NULL))               ||
 | 
						|
      EFI_IP4_EQUAL (&Token->RemoteAddress, &mZeroIp4Addr)
 | 
						|
      ) {
 | 
						|
    //
 | 
						|
    // The DHCP packet isn't well-formed, the Transaction ID is already used,
 | 
						|
    // the timeout value is zero, the ListenPoint is invalid, or the
 | 
						|
    // RemoteAddress is zero.
 | 
						|
    //
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (DhcpSb->ClientAddr == 0) {
 | 
						|
 | 
						|
    return EFI_NO_MAPPING;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
 | 
						|
  //
 | 
						|
  // Save the token and the timeout value.
 | 
						|
  //
 | 
						|
  Instance->Token   = Token;
 | 
						|
  Instance->Timeout = Token->TimeoutValue;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create a UDP IO for this transmit receive transaction.
 | 
						|
  //
 | 
						|
  Status = Dhcp4InstanceCreateUdpIo (Instance);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Save the Client Address is sent out
 | 
						|
  //
 | 
						|
  CopyMem (
 | 
						|
    &DhcpSb->ClientAddressSendOut[0],
 | 
						|
    &Token->Packet->Dhcp4.Header.ClientHwAddr[0],
 | 
						|
    Token->Packet->Dhcp4.Header.HwAddrLen
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Wrap the DHCP packet into a net buffer.
 | 
						|
  //
 | 
						|
  Frag.Bulk = (UINT8 *) &Token->Packet->Dhcp4;
 | 
						|
  Frag.Len  = Token->Packet->Length;
 | 
						|
  Wrap      = NetbufFromExt (&Frag, 1, 0, 0, DhcpDummyExtFree, NULL);
 | 
						|
  if (Wrap == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Set the local address and local port to ZERO.
 | 
						|
  //
 | 
						|
  ZeroMem (&EndPoint, sizeof (UDP_END_POINT));
 | 
						|
 | 
						|
  //
 | 
						|
  // Set the destination address and destination port.
 | 
						|
  //
 | 
						|
  CopyMem (&Ip, &Token->RemoteAddress, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
  EndPoint.RemoteAddr.Addr[0] = NTOHL (Ip);
 | 
						|
 | 
						|
  if (Token->RemotePort == 0) {
 | 
						|
    EndPoint.RemotePort = DHCP_SERVER_PORT;
 | 
						|
  } else {
 | 
						|
    EndPoint.RemotePort = Token->RemotePort;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the gateway.
 | 
						|
  //
 | 
						|
  SubnetMask = DhcpSb->Netmask;
 | 
						|
  ZeroMem (&Gateway, sizeof (Gateway));
 | 
						|
  if (!IP4_NET_EQUAL (DhcpSb->ClientAddr, EndPoint.RemoteAddr.Addr[0], SubnetMask)) {
 | 
						|
    CopyMem (&Gateway.v4, &Token->GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
    Gateway.Addr[0] = NTOHL (Gateway.Addr[0]);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Transmit the DHCP packet.
 | 
						|
  //
 | 
						|
  Status = UdpIoSendDatagram (Instance->UdpIo, Wrap, &EndPoint, &Gateway, DhcpOnPacketSent, NULL);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    NetbufFree (Wrap);
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Start to receive the DHCP response.
 | 
						|
  //
 | 
						|
  Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
 | 
						|
  if (EFI_ERROR (Status) && (Instance->UdpIo != NULL)) {
 | 
						|
    UdpIoCleanIo (Instance->UdpIo);
 | 
						|
    gBS->CloseProtocol (
 | 
						|
           Instance->UdpIo->UdpHandle,
 | 
						|
           &gEfiUdp4ProtocolGuid,
 | 
						|
           Instance->Service->Image,
 | 
						|
           Instance->Handle
 | 
						|
           );
 | 
						|
    UdpIoFreeIo (Instance->UdpIo);
 | 
						|
    Instance->UdpIo = NULL;
 | 
						|
    Instance->Token = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status) && (Token->CompletionEvent == NULL)) {
 | 
						|
    //
 | 
						|
    // Keep polling until timeout if no error happens and the CompletionEvent
 | 
						|
    // is NULL.
 | 
						|
    //
 | 
						|
    while (TRUE) {
 | 
						|
      OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
      //
 | 
						|
      // Raise TPL to protect the UDPIO in instance, in case that DhcpOnTimerTick
 | 
						|
      // free it when timeout.
 | 
						|
      //
 | 
						|
      if (Instance->Timeout > 0) {
 | 
						|
        Instance->UdpIo->Protocol.Udp4->Poll (Instance->UdpIo->Protocol.Udp4);
 | 
						|
        gBS->RestoreTPL (OldTpl);
 | 
						|
      } else {
 | 
						|
        gBS->RestoreTPL (OldTpl);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Callback function for DhcpIterateOptions. This callback sets the
 | 
						|
  EFI_DHCP4_PACKET_OPTION array in the DHCP_PARSE_CONTEXT to point
 | 
						|
  the individual DHCP option in the packet.
 | 
						|
 | 
						|
  @param[in]  Tag                    The DHCP option type
 | 
						|
  @param[in]  Len                    Length of the DHCP option data
 | 
						|
  @param[in]  Data                   The DHCP option data
 | 
						|
  @param[in]  Context                The context, to pass several parameters in.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            It always returns EFI_SUCCESS
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Dhcp4ParseCheckOption (
 | 
						|
  IN UINT8                  Tag,
 | 
						|
  IN UINT8                  Len,
 | 
						|
  IN UINT8                  *Data,
 | 
						|
  IN VOID                   *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  DHCP_PARSE_CONTEXT        *Parse;
 | 
						|
 | 
						|
  Parse = (DHCP_PARSE_CONTEXT *) Context;
 | 
						|
  Parse->Index++;
 | 
						|
 | 
						|
  if (Parse->Index <= Parse->OptionCount) {
 | 
						|
    //
 | 
						|
    // Use BASE_CR to get the memory position of EFI_DHCP4_PACKET_OPTION for
 | 
						|
    // the EFI_DHCP4_PACKET_OPTION->Data because DhcpIterateOptions only
 | 
						|
    // pass in the point to option data.
 | 
						|
    //
 | 
						|
    Parse->Option[Parse->Index - 1] = BASE_CR (Data, EFI_DHCP4_PACKET_OPTION, Data);
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Parses the packed DHCP option data.
 | 
						|
 | 
						|
  The Parse() function is used to retrieve the option list from a DHCP packet.
 | 
						|
  If *OptionCount isn't zero, and there is enough space for all the DHCP options
 | 
						|
  in the Packet, each element of PacketOptionList is set to point to somewhere in
 | 
						|
  the Packet->Dhcp4.Option where a new DHCP option begins. If RFC3396 is supported,
 | 
						|
  the caller should reassemble the parsed DHCP options to get the finial result.
 | 
						|
  If *OptionCount is zero or there isn't enough space for all of them, the number
 | 
						|
  of DHCP options in the Packet is returned in OptionCount.
 | 
						|
 | 
						|
  @param  This             Pointer to the EFI_DHCP4_PROTOCOL instance.
 | 
						|
  @param  Packet           Pointer to packet to be parsed.
 | 
						|
  @param  OptionCount      On input, the number of entries in the PacketOptionList.
 | 
						|
                           On output, the number of entries that were written into the
 | 
						|
                           PacketOptionList.
 | 
						|
  @param  PacketOptionList List of packet option entries to be filled in. End option or pad
 | 
						|
                           options are not included.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The packet was successfully parsed.
 | 
						|
  @retval EFI_INVALID_PARAMETER Some parameter is NULL.
 | 
						|
  @retval EFI_BUFFER_TOO_SMALL  One or more of the following conditions is TRUE:
 | 
						|
                                1) *OptionCount is smaller than the number of options that
 | 
						|
                                were found in the Packet.
 | 
						|
                                2) PacketOptionList is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiDhcp4Parse (
 | 
						|
  IN EFI_DHCP4_PROTOCOL       *This,
 | 
						|
  IN EFI_DHCP4_PACKET         *Packet,
 | 
						|
  IN OUT UINT32               *OptionCount,
 | 
						|
  OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  DHCP_PARSE_CONTEXT        Context;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // First validate the parameters
 | 
						|
  //
 | 
						|
  if ((This == NULL) || (Packet == NULL) || (OptionCount == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Packet->Size < Packet->Length + 2 * sizeof (UINT32)) ||
 | 
						|
      (Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||
 | 
						|
      EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {
 | 
						|
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((*OptionCount != 0) && (PacketOptionList == NULL)) {
 | 
						|
    return EFI_BUFFER_TOO_SMALL;
 | 
						|
  }
 | 
						|
 | 
						|
  ZeroMem (PacketOptionList, *OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
 | 
						|
 | 
						|
  Context.Option      = PacketOptionList;
 | 
						|
  Context.OptionCount = *OptionCount;
 | 
						|
  Context.Index       = 0;
 | 
						|
 | 
						|
  Status              = DhcpIterateOptions (Packet, Dhcp4ParseCheckOption, &Context);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  *OptionCount = Context.Index;
 | 
						|
 | 
						|
  if (Context.Index > Context.OptionCount) {
 | 
						|
    return EFI_BUFFER_TOO_SMALL;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set the elapsed time based on the given instance and the pointer to the
 | 
						|
  elapsed time option.
 | 
						|
 | 
						|
  @param[in]      Elapsed       The pointer to the position to append.
 | 
						|
  @param[in]      Instance      The pointer to the Dhcp4 instance.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SetElapsedTime (
 | 
						|
  IN     UINT16                 *Elapsed,
 | 
						|
  IN     DHCP_PROTOCOL          *Instance
 | 
						|
  )
 | 
						|
{
 | 
						|
  WriteUnaligned16 (Elapsed, HTONS(Instance->ElaspedTime));
 | 
						|
}
 |