/** @file
Functions implementation related with DHCPv4 for UefiPxeBc Driver.
Copyright (c) 2009 - 2011, 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
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 "PxeBcImpl.h"
//
// This is a map from the interested DHCP4 option tags' index to the tag value.
//
};
//
// There are 4 times retries with the value of 4, 8, 16 and 32, refers to PXE2.1 spec.
//
/**
Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.
@param[in] Buffer Pointer to the option buffer.
@param[in] Length Length of the option buffer.
@param[in] OptTag Tag of the required option.
@retval NULL Failed to find the required option.
@retval Others The position of the required option.
**/
)
{
Offset = 0;
//
// Found the required option.
//
return Option;
}
//
// Skip the current option to the next.
//
Offset++;
} else {
}
}
return NULL;
}
/**
Parse the PXE vender options and extract the information from them.
@param[in] Dhcp4Option Pointer to vendor options in buffer.
@param[in] VendorOption Pointer to structure to store information in vendor options.
**/
)
{
Offset = 0;
//
// Parse all the interesting PXE vendor options one by one.
//
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
default:
//
// Not interesting PXE vendor options.
//
break;
}
//
// Set the bit map for the special PXE options.
//
//
// Continue to the next option.
//
Offset++;
} else {
}
}
}
/**
Build the options buffer for the DHCPv4 request packet.
@param[in] Private Pointer to PxeBc private data.
@param[out] OptList Pointer to the option pointer array.
@param[in] Buffer Pointer to the buffer to contain the option list.
@param[in] NeedMsgType If TRUE, it is necessary to include the Msg type option.
Otherwise, it is not necessary.
@return Index The count of the built-in options.
**/
)
{
Index = 0;
if (NeedMsgType) {
//
// Append message type.
//
Index++;
//
// Append max message size.
//
Index++;
}
//
// Append parameter request list option.
//
Index++;
//
// Append UUID/Guid-based client identifier option
//
Index++;
//
// Zero the Guid to indicate NOT programable if failed to get system Guid.
//
}
//
// Append client network device interface option
//
} else {
}
Index++;
//
// Append client system architecture option
//
Index++;
//
// Append vendor class identify option
//
CopyMem (
sizeof (PXEBC_DHCP4_OPTION_CLID)
);
);
PxeBcUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));
PxeBcUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));
}
Index++;
return Index;
}
/**
Create a template DHCPv4 packet as a seed.
@param[out] Seed Pointer to the seed packet.
@param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL.
**/
)
{
//
// Get IfType and HwAddressSize from SNP mode data.
//
}
/**
Cache the DHCPv4 packet.
@param[in] Dst Pointer to the cache buffer for DHCPv4 packet.
@param[in] Src Pointer to the DHCPv4 packet to be cached.
**/
)
{
}
/**
Parse the cached DHCPv4 packet, including all the options.
@param[in] Cache4 Pointer to cached DHCPv4 packet.
@retval EFI_SUCCESS Parsed the DHCPv4 packet successfully.
@retval EFI_DEVICE_ERROR Failed to parse and invalid packet.
**/
)
{
IsPxeOffer = FALSE;
//
// Parse DHCPv4 options in this offer, and store the pointers.
//
);
}
//
// The offer with "yiaddr" is a proxy offer.
//
IsProxyOffer = TRUE;
}
//
// The offer with "PXEClient" is a PXE offer.
//
IsPxeOffer = TRUE;
}
//
//
}
//
// Check whether bootfilename and serverhostname overloaded, refers to rfc-2132 in details.
// If overloaded, parse the buffer as nested DHCPv4 options, or else just parse as bootfilename
// and serverhostname option.
//
);
//
// RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
// terminated string. So force to append null terminated character at the end of string.
//
*Ptr8 = '\0';
}
//
// If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.
// Do not count dhcp option header here, or else will destory the serverhostname.
//
}
//
// Determine offer type of the DHCPv4 packet.
//
//
// It's a Bootp offer.
//
//
// If the Bootp offer without bootfilename, discard it.
//
return EFI_DEVICE_ERROR;
}
} else {
//
// It's a PXE10 offer with PXEClient and discover vendor option.
//
//
// It's a WFM11a offer with PXEClient and mtftp vendor option.
// But multi-cast download is not supported currently, so discard it.
//
return EFI_DEVICE_ERROR;
} else if (IsPxeOffer) {
//
// It's a BINL offer only with PXEClient.
//
} else {
//
// It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet.
//
}
}
return EFI_SUCCESS;
}
/**
Cache the DHCPv4 ack packet, and parse it on demand.
@param[in] Private Pointer to PxeBc private data.
@param[in] Ack Pointer to the DHCPv4 ack packet.
@param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
**/
)
{
if (Verified) {
//
// Parse the ack packet and store it into mode data if needed.
//
}
}
/**
Cache the DHCPv4 proxy offer packet according to the received order.
@param[in] Private Pointer to PxeBc private data.
@param[in] OfferIndex The received order of offer packets.
**/
)
{
//
// Cache the proxy offer packet and parse it.
//
//
// Store this packet into mode data.
//
}
/**
Retry to request bootfile name by the BINL offer.
@param[in] Private Pointer to PxeBc private data.
@param[in] Index The received order of offer packets.
@retval EFI_SUCCESS Successfully retried to request bootfile name.
@retval EFI_DEVICE_ERROR Failed to retry bootfile name.
**/
)
{
//
// Prefer to siaddr in header as next server address. If it's zero, then use option 54.
//
CopyMem (
sizeof (EFI_IPv4_ADDRESS)
);
} else {
CopyMem (
sizeof (EFI_IPv4_ADDRESS)
);
}
//
// Send another request packet for bootfile name.
//
0,
NULL,
&ServerIp,
0,
);
return Status;
}
//
// Parse the reply for the last request packet.
//
return Status;
}
//
// This BINL ack doesn't have discovery option set or multicast option set
// or bootfile name specified.
//
return EFI_DEVICE_ERROR;
}
//
// Store the reply into mode data.
//
return EFI_SUCCESS;
}
/**
Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.
@param[in] Private Pointer to PxeBc private data.
@param[in] RcvdOffer Pointer to the received offer packet.
**/
)
{
//
// Cache the content of DHCPv4 packet firstly.
//
//
// Validate the DHCPv4 packet, and parse the options and offer type.
//
return;
}
//
// Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
//
if (OfferType == PxeOfferTypeBootp) {
//
// It's a Bootp offer, only cache the first one, and discard the others.
//
} else {
return;
}
} else {
if (IS_PROXY_DHCP_OFFER (Offer)) {
//
// It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
//
if (OfferType == PxeOfferTypeProxyBinl) {
//
// Cache all proxy BINL offers.
//
//
//
} else {
return ;
}
} else {
//
// It's a DHCPv4 offer with yiaddr, and cache them all.
//
}
}
}
/**
Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.
@param[in] Private Pointer to PxeBc private data.
**/
)
{
Private->SelectIndex = 0;
if (Private->IsOfferSorted) {
//
// Select offer by default policy.
//
//
// 1. DhcpPxe10 offer
//
//
// 2. DhcpWfm11a offer
//
//
// 3. DhcpOnly offer and ProxyPxe10 offer.
//
//
// 4. DhcpOnly offer and ProxyWfm11a offer.
//
//
// 5. DhcpBinl offer.
//
//
// 6. DhcpOnly offer and ProxyBinl offer.
//
} else {
//
// 7. DhcpOnly offer with bootfilename.
//
break;
}
}
//
// 8. Bootp offer with bootfilename.
//
if (Private->SelectIndex == 0 &&
}
}
} else {
//
// Select offer by received order.
//
if (IS_PROXY_DHCP_OFFER (Offer)) {
//
// Skip proxy offers
//
continue;
}
if (!Private->IsProxyRecved &&
//
// Skip if DhcpOnly offer without any other proxy offers or bootfilename.
//
continue;
}
//
// Record the index of the select offer.
//
break;
}
}
}
/**
Handle the DHCPv4 offer packet.
@param[in] Private Pointer to PxeBc private data.
@retval EFI_SUCCESS Handled the DHCPv4 offer packet successfully.
@retval EFI_NO_RESPONSE No response to the following request packet.
@retval EFI_NOT_FOUND No boot filename received.
**/
)
{
//
// DhcpBinl offer is selected, so need try to request bootfilename by this offer.
//
}
if (Private->IsProxyRecved) {
//
// DhcpOnly offer is selected, so need try to request bootfile name.
//
ProxyIndex = 0;
if (Private->IsOfferSorted) {
//
// The proxy offer should be determined if select by default policy.
// IsOfferSorted means all offers are labeled by OfferIndex.
//
//
// Try all the cached ProxyBinl offer one by one to request bootfile name.
//
break;
}
}
}
} else {
//
// For other proxy offers, only one is buffered.
//
}
} else {
//
// The proxy offer should not be determined if select by received order.
//
if (!IS_PROXY_DHCP_OFFER (Offer)) {
//
// Skip non proxy DHCPv4 offers.
//
continue;
}
if (OfferType == PxeOfferTypeProxyBinl) {
//
// Try all the cached ProxyBinl offer one by one to request bootfile name.
//
continue;
}
}
ProxyIndex = Index;
break;
}
}
//
// Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
//
}
} else {
//
// Othewise, the bootfile name must be included in DhcpOnly offer.
//
}
}
}
//
// All PXE boot information is ready by now.
//
//
// Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply
// should be taken as ack.
//
}
}
return Status;
}
/**
EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
to intercept events that occurred in the configuration process.
@param[in] This Pointer to the EFI DHCPv4 Protocol.
@param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().
@param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.
@param[in] Dhcp4Event The event that occurs in the current state, which usually means a
state transition.
@param[in] Packet The DHCPv4 packet that is going to be sent or already received.
@param[out] NewPacket The packet that is used to replace the above Packet.
@retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
@retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
driver will continue to wait for more DHCPOFFER packets until the
retry timeout expires.
@retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process
and return to the Dhcp4Init or Dhcp4InitReboot state.
**/
)
{
if ((Dhcp4Event != Dhcp4RcvdOffer) &&
(Dhcp4Event != Dhcp4SelectOffer) &&
(Dhcp4Event != Dhcp4SendDiscover) &&
(Dhcp4Event != Dhcp4RcvdAck)) {
return EFI_SUCCESS;
}
//
// Override the Maximum DHCP Message Size.
//
);
if (MaxMsgSize != NULL) {
}
//
// Callback to user if any packets sent or received.
//
);
return EFI_ABORTED;
}
}
switch (Dhcp4Event) {
case Dhcp4SendDiscover:
//
// Cache the DHCPv4 discover packet to mode data directly.
// It need to check SendGuid as well as Dhcp4SendRequest.
//
case Dhcp4SendRequest:
//
// Send the system Guid instead of the MAC address as the hardware address if required.
//
//
// Zero the Guid to indicate NOT programable if failed to get system Guid.
//
}
}
break;
case Dhcp4RcvdOffer:
//
// Cache the DHCPv4 offers to OfferBuffer[] for select later, and record
// the OfferIndex and OfferCount.
//
}
break;
case Dhcp4SelectOffer:
//
// Select offer by the default policy or by order, and record the SelectIndex
// and SelectProxyType.
//
if (Private->SelectIndex == 0) {
} else {
}
break;
case Dhcp4RcvdAck:
//
// Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data
// without verification.
//
break;
default:
break;
}
return Status;
}
/**
Build and send out the request packet for the bootfile, and parse the reply.
@param[in] Private Pointer to PxeBc private data.
@param[in] Type PxeBc option boot item type.
@param[in] Layer Pointer to option boot item layer.
@param[in] UseBis Use BIS or not.
@param[in] DestIp Pointer to the server address.
@param[in] IpCount The total count of the server address.
@param[in] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.
@retval EFI_SUCCESS Successfully discovered boot file.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
@retval EFI_NOT_FOUND Can't get the PXE reply packet.
@retval Others Failed to discover boot file.
**/
)
{
//
// Use broadcast if destination address not specified.
//
} else {
}
}
//
// Build all the options for the request packet.
//
if (Private->IsDoDiscover) {
//
// Add vendor option of PXE_BOOT_ITEM
//
VendorOptLen = (UINT8) ((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1);
return EFI_OUT_OF_RESOURCES;
}
}
OptCount++;
}
//
// Build the request packet with seed packet and option list.
//
0,
NULL,
);
//
// Free the vendor option of PXE_BOOT_ITEM.
//
if (Private->IsDoDiscover) {
}
return Status;
}
//
// Zero the Guid to indicate NOT programable if failed to get system Guid.
//
}
}
//
// Set fields of the token for the request packet.
//
if (IsBCast) {
} else {
}
if (!IsBCast) {
}
//
// Send out the request packet to discover the bootfile.
//
break;
}
}
if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) {
//
// No server response our PXE request
//
}
RepIndex = 0;
SrvIndex = 0;
//
// Find the right PXE Reply according to server address.
//
break;
}
break;
}
SrvIndex++;
}
break;
}
SrvIndex = 0;
RepIndex++;
}
//
// Cache the right PXE reply packet here, set valid flag later.
// Especially for PXE discover packet, store it into mode data here.
//
if (Private->IsDoDiscover) {
} else {
}
} else {
//
// Not found the right PXE reply packet.
//
}
}
}
return Status;
}
/**
Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information.
@param[in] Private Pointer to PxeBc private data.
@param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL
@retval EFI_SUCCESS The D.O.R.A process successfully finished.
@retval Others Failed to finish the D.O.R.A process.
**/
)
{
//
// Build option list for the request packet.
//
//
// Configure the DHCPv4 instance for PXE boot.
//
goto ON_EXIT;
}
//
// Initialize the record fields for DHCPv4 offer in private data.
//
//
// Start DHCPv4 D.O.R.A. process to acquire IPv4 address.
//
if (Status == EFI_ICMP_ERROR) {
}
goto ON_EXIT;
}
//
// Get the acquired IPv4 address and store them.
//
goto ON_EXIT;
}
goto ON_EXIT;
}
//
// Check the selected offer whether BINL retry is needed.
//
AsciiPrint ("\n Station IP address is ");
} else {
}
return Status;
}