mirror of https://github.com/acidanthera/audk.git
NetworkPkg: Add UEFI HTTP boot driver.
This patch add the implementation for UEFI HTTP boot driver. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Ye Ting <ting.ye@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17857 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
eb4d0b5e85
commit
c4545d769f
|
@ -0,0 +1,830 @@
|
|||
/** @file
|
||||
Implementation of the boot file download function.
|
||||
|
||||
Copyright (c) 2015, 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 that 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 "HttpBootDxe.h"
|
||||
|
||||
/**
|
||||
Update the IP and URL device path node to include the boot resource information.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
|
||||
@retval EFI_SUCCESS Device patch successfully updated.
|
||||
@retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
|
||||
@retval Others Unexpected error happened.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootUpdateDevicePath (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
EFI_DEV_PATH *Node;
|
||||
EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
|
||||
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
|
||||
UINTN Length;
|
||||
EFI_STATUS Status;
|
||||
|
||||
TmpDevicePath = NULL;
|
||||
|
||||
//
|
||||
// Update the IP node with DHCP assigned information.
|
||||
//
|
||||
if (!Private->UsingIpv6) {
|
||||
Node = AllocateZeroPool (sizeof (IPv4_DEVICE_PATH));
|
||||
if (Node == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
Node->Ipv4.Header.Type = MESSAGING_DEVICE_PATH;
|
||||
Node->Ipv4.Header.SubType = MSG_IPv4_DP;
|
||||
SetDevicePathNodeLength (Node, sizeof (IPv4_DEVICE_PATH));
|
||||
CopyMem (&Node->Ipv4.LocalIpAddress, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
|
||||
Node->Ipv4.RemotePort = Private->Port;
|
||||
Node->Ipv4.Protocol = EFI_IP_PROTO_TCP;
|
||||
Node->Ipv4.StaticIpAddress = FALSE;
|
||||
CopyMem (&Node->Ipv4.GatewayIpAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));
|
||||
CopyMem (&Node->Ipv4.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
|
||||
|
||||
TmpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
|
||||
FreePool (Node);
|
||||
if (TmpDevicePath == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
} else {
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
|
||||
//
|
||||
// Update the URI node with the boot file URI.
|
||||
//
|
||||
Length = sizeof (EFI_DEVICE_PATH_PROTOCOL) + AsciiStrSize (Private->BootFileUri);
|
||||
Node = AllocatePool (Length);
|
||||
if (Node == NULL) {
|
||||
FreePool (TmpDevicePath);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
Node->DevPath.Type = MESSAGING_DEVICE_PATH;
|
||||
Node->DevPath.SubType = MSG_URI_DP;
|
||||
SetDevicePathNodeLength (Node, Length);
|
||||
CopyMem ((UINT8*) Node + sizeof (EFI_DEVICE_PATH_PROTOCOL), Private->BootFileUri, AsciiStrSize (Private->BootFileUri));
|
||||
|
||||
NewDevicePath = AppendDevicePathNode (TmpDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
|
||||
FreePool (Node);
|
||||
FreePool (TmpDevicePath);
|
||||
if (NewDevicePath == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
//
|
||||
// Reinstall the device path protocol of the child handle.
|
||||
//
|
||||
Status = gBS->ReinstallProtocolInterface (
|
||||
Private->ChildHandle,
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
Private->DevicePath,
|
||||
NewDevicePath
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
FreePool (Private->DevicePath);
|
||||
Private->DevicePath = NewDevicePath;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Parse the boot file URI information from the selected Dhcp4 offer packet.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
|
||||
@retval EFI_SUCCESS Successfully parsed out all the boot information.
|
||||
@retval Others Failed to parse out the boot information.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootExtractUriInfo (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
HTTP_BOOT_DHCP4_PACKET_CACHE *SelectOffer;
|
||||
HTTP_BOOT_DHCP4_PACKET_CACHE *HttpOffer;
|
||||
UINT32 SelectIndex;
|
||||
UINT32 ProxyIndex;
|
||||
EFI_DHCP4_PACKET_OPTION *Option;
|
||||
EFI_STATUS Status;
|
||||
|
||||
ASSERT (Private != NULL);
|
||||
ASSERT (Private->SelectIndex != 0);
|
||||
SelectIndex = Private->SelectIndex - 1;
|
||||
ASSERT (SelectIndex < HTTP_BOOT_OFFER_MAX_NUM);
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
|
||||
//
|
||||
// SelectOffer contains the IP address configuration and name server configuration.
|
||||
// HttpOffer contains the boot file URL.
|
||||
//
|
||||
SelectOffer = &Private->OfferBuffer[SelectIndex].Dhcp4;
|
||||
if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) || (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns)) {
|
||||
HttpOffer = SelectOffer;
|
||||
} else {
|
||||
ASSERT (Private->SelectProxyType != HttpOfferTypeMax);
|
||||
ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
|
||||
HttpOffer = &Private->OfferBuffer[ProxyIndex].Dhcp4;
|
||||
}
|
||||
|
||||
//
|
||||
// Configure the default DNS server if server assigned.
|
||||
//
|
||||
if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) || (SelectOffer->OfferType == HttpOfferTypeDhcpDns)) {
|
||||
Option = SelectOffer->OptList[HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER];
|
||||
ASSERT (Option != NULL);
|
||||
Status = HttpBootRegisterIp4Dns (
|
||||
Private,
|
||||
Option->Length,
|
||||
Option->Data
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Extract the port from URL, and use default HTTP port 80 if not provided.
|
||||
//
|
||||
Status = HttpUrlGetPort (
|
||||
(CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data,
|
||||
HttpOffer->UriParser,
|
||||
&Private->Port
|
||||
);
|
||||
if (EFI_ERROR (Status) || Private->Port == 0) {
|
||||
Private->Port = 80;
|
||||
}
|
||||
|
||||
//
|
||||
// Record the URI of boot file from the selected HTTP offer.
|
||||
//
|
||||
Private->BootFileUriParser = HttpOffer->UriParser;
|
||||
Private->BootFileUri = (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data;
|
||||
|
||||
|
||||
//
|
||||
// All boot informations are valid here.
|
||||
//
|
||||
AsciiPrint ("\n URI: %a", Private->BootFileUri);
|
||||
|
||||
//
|
||||
// Update the device path to include the IP and boot URI information.
|
||||
//
|
||||
Status = HttpBootUpdateDevicePath (Private);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Discover all the boot information for boot file.
|
||||
|
||||
@param[in, out] Private The pointer to the driver's private data.
|
||||
|
||||
@retval EFI_SUCCESS Successfully obtained all the boot information .
|
||||
@retval Others Failed to retrieve the boot information.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootDiscoverBootInfo (
|
||||
IN OUT HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// Start D.O.R.A/S.A.R.R exchange to acquire station ip address and
|
||||
// other Http boot information.
|
||||
//
|
||||
Status = HttpBootDhcp (Private);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (!Private->UsingIpv6) {
|
||||
Status = HttpBootExtractUriInfo (Private);
|
||||
} else {
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Create a HttpIo instance for the file download.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
|
||||
@retval EFI_SUCCESS Successfully created.
|
||||
@retval Others Failed to create HttpIo.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootCreateHttpIo (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
HTTP_IO_CONFIG_DATA ConfigData;
|
||||
EFI_STATUS Status;
|
||||
|
||||
ASSERT (Private != NULL);
|
||||
|
||||
ZeroMem (&ConfigData, sizeof (HTTP_IO_CONFIG_DATA));
|
||||
if (!Private->UsingIpv6) {
|
||||
ConfigData.Config4.HttpVersion = HttpVersion11;
|
||||
ConfigData.Config4.RequestTimeOut = HTTP_BOOT_REQUEST_TIMEOUT;
|
||||
IP4_COPY_ADDRESS (&ConfigData.Config4.LocalIp, &Private->StationIp.v4);
|
||||
IP4_COPY_ADDRESS (&ConfigData.Config4.SubnetMask, &Private->SubnetMask.v4);
|
||||
} else {
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
|
||||
Status = HttpIoCreateIo (
|
||||
Private->Image,
|
||||
Private->Controller,
|
||||
Private->UsingIpv6 ? IP_VERSION_6 : IP_VERSION_4,
|
||||
&ConfigData,
|
||||
&Private->HttpIo
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Private->HttpCreated = TRUE;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the file content from cached data.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
@param[in] Uri Uri of the file to be retrieved from cache.
|
||||
@param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
|
||||
code of EFI_SUCCESS, the amount of data transferred to
|
||||
Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
|
||||
the size of Buffer required to retrieve the requested file.
|
||||
@param[out] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
|
||||
then the size of the requested file is returned in
|
||||
BufferSize.
|
||||
|
||||
@retval EFI_SUCCESS Successfully created.
|
||||
@retval Others Failed to create HttpIo.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootGetFileFromCache (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private,
|
||||
IN CHAR16 *Uri,
|
||||
IN OUT UINTN *BufferSize,
|
||||
OUT UINT8 *Buffer
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *Entry2;
|
||||
HTTP_BOOT_CACHE_CONTENT *Cache;
|
||||
HTTP_BOOT_ENTITY_DATA *EntityData;
|
||||
UINTN CopyedSize;
|
||||
|
||||
if (Uri == NULL || BufferSize == 0 || Buffer == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
NET_LIST_FOR_EACH (Entry, &Private->CacheList) {
|
||||
Cache = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_CACHE_CONTENT, Link);
|
||||
//
|
||||
// Compare the URI to see whether we already have a cache for this file.
|
||||
//
|
||||
if ((Cache->RequestData != NULL) &&
|
||||
(Cache->RequestData->Url != NULL) &&
|
||||
(StrCmp (Uri, Cache->RequestData->Url) == 0))
|
||||
{
|
||||
//
|
||||
// Hit cache, check buffer size.
|
||||
//
|
||||
if (*BufferSize < Cache->EntityLength) {
|
||||
*BufferSize = Cache->EntityLength;
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
//
|
||||
// Fill data to buffer.
|
||||
//
|
||||
CopyedSize = 0;
|
||||
NET_LIST_FOR_EACH (Entry2, &Cache->EntityDataList) {
|
||||
EntityData = NET_LIST_USER_STRUCT (Entry2, HTTP_BOOT_ENTITY_DATA, Link);
|
||||
if (*BufferSize > CopyedSize) {
|
||||
CopyMem (
|
||||
Buffer + CopyedSize,
|
||||
EntityData->DataStart,
|
||||
MIN (EntityData->DataLength, *BufferSize - CopyedSize)
|
||||
);
|
||||
CopyedSize += MIN (EntityData->DataLength, *BufferSize - CopyedSize);
|
||||
}
|
||||
}
|
||||
*BufferSize = CopyedSize;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
Release all the resource of a cache item.
|
||||
|
||||
@param[in] Cache The pointer to the cache item.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootFreeCache (
|
||||
IN HTTP_BOOT_CACHE_CONTENT *Cache
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *NextEntry;
|
||||
HTTP_BOOT_ENTITY_DATA *EntityData;
|
||||
|
||||
if (Cache != NULL) {
|
||||
//
|
||||
// Free the request data
|
||||
//
|
||||
if (Cache->RequestData != NULL) {
|
||||
if (Cache->RequestData->Url != NULL) {
|
||||
FreePool (Cache->RequestData->Url);
|
||||
}
|
||||
FreePool (Cache->RequestData);
|
||||
}
|
||||
|
||||
//
|
||||
// Free the response header
|
||||
//
|
||||
if (Cache->ResponseData != NULL) {
|
||||
if (Cache->ResponseData->Headers != NULL) {
|
||||
for (Index = 0; Index < Cache->ResponseData->HeaderCount; Index++) {
|
||||
FreePool (Cache->ResponseData->Headers[Index].FieldName);
|
||||
FreePool (Cache->ResponseData->Headers[Index].FieldValue);
|
||||
}
|
||||
FreePool (Cache->ResponseData->Headers);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Free the response body
|
||||
//
|
||||
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Cache->EntityDataList) {
|
||||
EntityData = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_ENTITY_DATA, Link);
|
||||
if (EntityData->Block != NULL) {
|
||||
FreePool (EntityData->Block);
|
||||
}
|
||||
RemoveEntryList (&EntityData->Link);
|
||||
FreePool (EntityData);
|
||||
}
|
||||
|
||||
FreePool (Cache);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Clean up all cached data.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootFreeCacheList (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *NextEntry;
|
||||
HTTP_BOOT_CACHE_CONTENT *Cache;
|
||||
|
||||
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->CacheList) {
|
||||
Cache = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_CACHE_CONTENT, Link);
|
||||
RemoveEntryList (&Cache->Link);
|
||||
HttpBootFreeCache (Cache);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
A callback function to intercept events during message parser.
|
||||
|
||||
This function will be invoked during HttpParseMessageBody() with various events type. An error
|
||||
return status of the callback function will cause the HttpParseMessageBody() aborted.
|
||||
|
||||
@param[in] EventType Event type of this callback call.
|
||||
@param[in] Data A pointer to data buffer.
|
||||
@param[in] Length Length in bytes of the Data.
|
||||
@param[in] Context Callback context set by HttpInitMsgParser().
|
||||
|
||||
@retval EFI_SUCCESS Continue to parser the message body.
|
||||
@retval Others Abort the parse.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootGetBootFileCallback (
|
||||
IN HTTP_BODY_PARSE_EVENT EventType,
|
||||
IN CHAR8 *Data,
|
||||
IN UINTN Length,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
HTTP_BOOT_CALLBACK_DATA *CallbackData;
|
||||
HTTP_BOOT_ENTITY_DATA *NewEntityData;
|
||||
|
||||
//
|
||||
// We only care about the entity data.
|
||||
//
|
||||
if (EventType != BodyParseEventOnData) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
CallbackData = (HTTP_BOOT_CALLBACK_DATA *) Context;
|
||||
|
||||
//
|
||||
// Save the data into cache list.
|
||||
//
|
||||
NewEntityData = AllocatePool (sizeof (HTTP_BOOT_ENTITY_DATA));
|
||||
if (NewEntityData == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
if (CallbackData->NewBlock) {
|
||||
NewEntityData->Block = CallbackData->Block;
|
||||
CallbackData->Block = NULL;
|
||||
}
|
||||
NewEntityData->DataLength = Length;
|
||||
NewEntityData->DataStart = (UINT8*) Data;
|
||||
InsertTailList (&CallbackData->Cache->EntityDataList, &NewEntityData->Link);
|
||||
|
||||
//
|
||||
// Copy data if caller has provided a buffer.
|
||||
//
|
||||
if (CallbackData->BufferSize > CallbackData->CopyedSize) {
|
||||
CopyMem (
|
||||
CallbackData->Buffer + CallbackData->CopyedSize,
|
||||
Data,
|
||||
MIN (Length, CallbackData->BufferSize - CallbackData->CopyedSize)
|
||||
);
|
||||
CallbackData->CopyedSize += MIN (Length, CallbackData->BufferSize - CallbackData->CopyedSize);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
This function download the boot file by using UEFI HTTP protocol.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
@param[in] HeaderOnly Only request the response header, it could save a lot of time if
|
||||
the caller only want to know the size of the requested file.
|
||||
@param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
|
||||
code of EFI_SUCCESS, the amount of data transferred to
|
||||
Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
|
||||
the size of Buffer required to retrieve the requested file.
|
||||
@param[out] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
|
||||
then the size of the requested file is returned in
|
||||
BufferSize.
|
||||
|
||||
@retval EFI_SUCCESS The file was loaded.
|
||||
@retval EFI_INVALID_PARAMETER BufferSize is NULL or Buffer Size is not NULL but Buffer is NULL.
|
||||
@retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
|
||||
@retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
|
||||
BufferSize has been updated with the size needed to complete
|
||||
the request.
|
||||
@retval Others Unexpected error happened.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootGetBootFile (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private,
|
||||
IN BOOLEAN HeaderOnly,
|
||||
IN OUT UINTN *BufferSize,
|
||||
OUT UINT8 *Buffer
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
CHAR8 *HostName;
|
||||
EFI_HTTP_REQUEST_DATA *RequestData;
|
||||
HTTP_IO_RESOPNSE_DATA *ResponseData;
|
||||
HTTP_IO_RESOPNSE_DATA ResponseBody;
|
||||
HTTP_IO *HttpIo;
|
||||
HTTP_IO_HEADER *HttpIoHeader;
|
||||
VOID *Parser;
|
||||
HTTP_BOOT_CALLBACK_DATA Context;
|
||||
UINTN ContentLength;
|
||||
HTTP_BOOT_CACHE_CONTENT *Cache;
|
||||
UINT8 *Block;
|
||||
CHAR16 *Url;
|
||||
|
||||
ASSERT (Private != NULL);
|
||||
ASSERT (Private->HttpCreated);
|
||||
|
||||
if (BufferSize == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (*BufferSize != 0 && Buffer == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// First, check whether we already cached the requested Uri.
|
||||
//
|
||||
Url = AllocatePool ((AsciiStrLen (Private->BootFileUri) + 1) * sizeof (CHAR16));
|
||||
if (Url == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
AsciiStrToUnicodeStr (Private->BootFileUri, Url);
|
||||
if (!HeaderOnly) {
|
||||
Status = HttpBootGetFileFromCache (Private, Url, BufferSize, Buffer);
|
||||
if (Status != EFI_NOT_FOUND) {
|
||||
FreePool (Url);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Not found in cache, try to download it through HTTP.
|
||||
//
|
||||
|
||||
//
|
||||
// 1. Create a temp cache item for the requested URI.
|
||||
//
|
||||
Cache = NULL;
|
||||
if (!HeaderOnly) {
|
||||
Cache = AllocateZeroPool (sizeof (HTTP_BOOT_CACHE_CONTENT));
|
||||
if (Cache == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ERROR_1;
|
||||
}
|
||||
InitializeListHead (&Cache->EntityDataList);
|
||||
}
|
||||
|
||||
//
|
||||
// 2. Send HTTP request message.
|
||||
//
|
||||
|
||||
//
|
||||
// 2.1 Build HTTP header for the request, 3 header is needed to download a boot file:
|
||||
// Host
|
||||
// Accept
|
||||
// User-Agent
|
||||
//
|
||||
HttpIoHeader = HttpBootCreateHeader (3);
|
||||
if (HttpIoHeader == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ERROR_2;
|
||||
}
|
||||
|
||||
//
|
||||
// Add HTTP header field 1: Host
|
||||
//
|
||||
HostName = NULL;
|
||||
Status = HttpUrlGetHostName (
|
||||
Private->BootFileUri,
|
||||
Private->BootFileUriParser,
|
||||
&HostName
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ERROR_3;
|
||||
}
|
||||
Status = HttpBootSetHeader (
|
||||
HttpIoHeader,
|
||||
HTTP_FIELD_NAME_HOST,
|
||||
HostName
|
||||
);
|
||||
FreePool (HostName);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ERROR_3;
|
||||
}
|
||||
|
||||
//
|
||||
// Add HTTP header field 2: Accept
|
||||
//
|
||||
Status = HttpBootSetHeader (
|
||||
HttpIoHeader,
|
||||
HTTP_FIELD_NAME_ACCEPT,
|
||||
"*/*"
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ERROR_3;
|
||||
}
|
||||
|
||||
//
|
||||
// Add HTTP header field 3: User-Agent
|
||||
//
|
||||
Status = HttpBootSetHeader (
|
||||
HttpIoHeader,
|
||||
HTTP_FIELD_NAME_USER_AGENT,
|
||||
HTTP_USER_AGENT_EFI_HTTP_BOOT
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ERROR_3;
|
||||
}
|
||||
|
||||
//
|
||||
// 2.2 Build the rest of HTTP request info.
|
||||
//
|
||||
RequestData = AllocatePool (sizeof (EFI_HTTP_REQUEST_DATA));
|
||||
if (RequestData == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ERROR_3;
|
||||
}
|
||||
RequestData->Method = HeaderOnly ? HttpMethodHead : HttpMethodGet;
|
||||
RequestData->Url = Url;
|
||||
if (RequestData->Url == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ERROR_4;
|
||||
}
|
||||
AsciiStrToUnicodeStr (Private->BootFileUri, RequestData->Url);
|
||||
|
||||
//
|
||||
// 2.3 Record the request info in a temp cache item.
|
||||
//
|
||||
if (!HeaderOnly) {
|
||||
Cache->RequestData = RequestData;
|
||||
}
|
||||
|
||||
//
|
||||
// 2.4 Send out the request to HTTP server.
|
||||
//
|
||||
HttpIo = &Private->HttpIo;
|
||||
Status = HttpIoSendRequest (
|
||||
HttpIo,
|
||||
RequestData,
|
||||
HttpIoHeader->HeaderCount,
|
||||
HttpIoHeader->Headers,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ERROR_4;
|
||||
}
|
||||
|
||||
//
|
||||
// 3. Receive HTTP response message.
|
||||
//
|
||||
|
||||
//
|
||||
// 3.1 First step, use zero BodyLength to only receive the response headers.
|
||||
//
|
||||
ResponseData = AllocateZeroPool (sizeof(HTTP_IO_RESOPNSE_DATA));
|
||||
if (ResponseData == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ERROR_4;
|
||||
}
|
||||
Status = HttpIoRecvResponse (
|
||||
&Private->HttpIo,
|
||||
TRUE,
|
||||
ResponseData
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ERROR_5;
|
||||
}
|
||||
|
||||
//
|
||||
// 3.2 Cache the response header.
|
||||
//
|
||||
if (!HeaderOnly) {
|
||||
Cache->ResponseData = ResponseData;
|
||||
}
|
||||
|
||||
//
|
||||
// 3.3 Init a message-body parser from the header information.
|
||||
//
|
||||
Parser = NULL;
|
||||
Context.NewBlock = FALSE;
|
||||
Context.Block = NULL;
|
||||
Context.CopyedSize = 0;
|
||||
Context.Buffer = Buffer;
|
||||
Context.BufferSize = *BufferSize;
|
||||
Context.Cache = Cache;
|
||||
Status = HttpInitMsgParser (
|
||||
HeaderOnly? HttpMethodHead : HttpMethodGet,
|
||||
ResponseData->Response.StatusCode,
|
||||
ResponseData->HeaderCount,
|
||||
ResponseData->Headers,
|
||||
HttpBootGetBootFileCallback,
|
||||
(VOID*) &Context,
|
||||
&Parser
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ERROR_6;
|
||||
}
|
||||
|
||||
//
|
||||
// 3.4 Continue to receive and parse message-body if needed.
|
||||
//
|
||||
if (!HeaderOnly) {
|
||||
ZeroMem (&ResponseBody, sizeof (HTTP_IO_RESOPNSE_DATA));
|
||||
while (!HttpIsMessageComplete (Parser)) {
|
||||
//
|
||||
// Allocate a new block to hold the message-body.
|
||||
//
|
||||
Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE);
|
||||
if (Block == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ERROR_6;
|
||||
}
|
||||
ResponseBody.Body = (CHAR8*) Block;
|
||||
ResponseBody.BodyLength = HTTP_BOOT_BLOCK_SIZE;
|
||||
Status = HttpIoRecvResponse (
|
||||
&Private->HttpIo,
|
||||
FALSE,
|
||||
&ResponseBody
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ERROR_6;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse the new received block of the message-body, the block will be saved in cache.
|
||||
//
|
||||
Context.NewBlock = TRUE;
|
||||
Context.Block = Block;
|
||||
Status = HttpParseMessageBody (
|
||||
Parser,
|
||||
ResponseBody.BodyLength,
|
||||
ResponseBody.Body
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ERROR_6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 3.5 Message-body receive & parse is completed, get the file size.
|
||||
//
|
||||
Status = HttpGetEntityLength (Parser, &ContentLength);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ERROR_6;
|
||||
}
|
||||
|
||||
if (*BufferSize < ContentLength) {
|
||||
Status = EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
*BufferSize = ContentLength;
|
||||
|
||||
//
|
||||
// 4. Save the cache item to driver's cache list and return.
|
||||
//
|
||||
if (!HeaderOnly) {
|
||||
Cache->EntityLength = ContentLength;
|
||||
InsertTailList (&Private->CacheList, &Cache->Link);
|
||||
}
|
||||
|
||||
if (Parser != NULL) {
|
||||
HttpFreeMsgParser (Parser);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
ERROR_6:
|
||||
if (Parser != NULL) {
|
||||
HttpFreeMsgParser (Parser);
|
||||
}
|
||||
if (Context.Block != NULL) {
|
||||
FreePool (Context.Block);
|
||||
}
|
||||
HttpBootFreeCache (Cache);
|
||||
|
||||
ERROR_5:
|
||||
if (ResponseData != NULL) {
|
||||
FreePool (ResponseData);
|
||||
}
|
||||
ERROR_4:
|
||||
if (RequestData != NULL) {
|
||||
FreePool (RequestData);
|
||||
}
|
||||
ERROR_3:
|
||||
HttpBootFreeHeader (HttpIoHeader);
|
||||
ERROR_2:
|
||||
if (Cache != NULL) {
|
||||
FreePool (Cache);
|
||||
}
|
||||
ERROR_1:
|
||||
if (Url != NULL) {
|
||||
FreePool (Url);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
/** @file
|
||||
Declaration of the boot file download function.
|
||||
|
||||
Copyright (c) 2015, 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 that 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.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __EFI_HTTP_BOOT_HTTP_H__
|
||||
#define __EFI_HTTP_BOOT_HTTP_H__
|
||||
|
||||
#define HTTP_BOOT_REQUEST_TIMEOUT 5000 // 5 seconds in uints of millisecond.
|
||||
#define HTTP_BOOT_BLOCK_SIZE 1024
|
||||
|
||||
#define HTTP_FIELD_NAME_USER_AGENT "User-Agent"
|
||||
#define HTTP_FIELD_NAME_HOST "Host"
|
||||
#define HTTP_FIELD_NAME_ACCEPT "Accept"
|
||||
|
||||
|
||||
#define HTTP_USER_AGENT_EFI_HTTP_BOOT "UefiHttpBoot/1.0"
|
||||
|
||||
//
|
||||
// Record the data length and start address of a data block.
|
||||
//
|
||||
typedef struct {
|
||||
LIST_ENTRY Link; // Link to the EntityDataList in HTTP_BOOT_CACHE_CONTENT
|
||||
UINT8 *Block; // If NULL, the data is in previous data block.
|
||||
UINT8 *DataStart; // Point to somewhere in the Block
|
||||
UINTN DataLength;
|
||||
} HTTP_BOOT_ENTITY_DATA;
|
||||
|
||||
//
|
||||
// Structure for a cache item
|
||||
//
|
||||
typedef struct {
|
||||
LIST_ENTRY Link; // Link to the CacheList in driver's private data.
|
||||
EFI_HTTP_REQUEST_DATA *RequestData;
|
||||
HTTP_IO_RESOPNSE_DATA *ResponseData; // Not include any message-body data.
|
||||
UINTN EntityLength;
|
||||
LIST_ENTRY EntityDataList; // Entity data (message-body)
|
||||
} HTTP_BOOT_CACHE_CONTENT;
|
||||
|
||||
//
|
||||
// Callback data for HTTP_BODY_PARSER_CALLBACK()
|
||||
//
|
||||
typedef struct {
|
||||
EFI_STATUS Status;
|
||||
//
|
||||
// Cache info.
|
||||
//
|
||||
HTTP_BOOT_CACHE_CONTENT *Cache;
|
||||
BOOLEAN NewBlock;
|
||||
UINT8 *Block;
|
||||
|
||||
//
|
||||
// Caller provided buffer to load the file in.
|
||||
//
|
||||
UINTN CopyedSize;
|
||||
UINTN BufferSize;
|
||||
UINT8 *Buffer;
|
||||
} HTTP_BOOT_CALLBACK_DATA;
|
||||
|
||||
/**
|
||||
Discover all the boot information for boot file.
|
||||
|
||||
@param[in, out] Private The pointer to the driver's private data.
|
||||
|
||||
@retval EFI_SUCCESS Successfully obtained all the boot information .
|
||||
@retval Others Failed to retrieve the boot information.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootDiscoverBootInfo (
|
||||
IN OUT HTTP_BOOT_PRIVATE_DATA *Private
|
||||
);
|
||||
|
||||
/**
|
||||
Create a HttpIo instance for the file download.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
|
||||
@retval EFI_SUCCESS Successfully created.
|
||||
@retval Others Failed to create HttpIo.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootCreateHttpIo (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
);
|
||||
|
||||
/**
|
||||
This function download the boot file by using UEFI HTTP protocol.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
@param[in] HeaderOnly Only request the response header, it could save a lot of time if
|
||||
the caller only want to know the size of the requested file.
|
||||
@param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
|
||||
code of EFI_SUCCESS, the amount of data transferred to
|
||||
Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
|
||||
the size of Buffer required to retrieve the requested file.
|
||||
@param[out] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
|
||||
then the size of the requested file is returned in
|
||||
BufferSize.
|
||||
|
||||
@retval EFI_SUCCESS The file was loaded.
|
||||
@retval EFI_INVALID_PARAMETER BufferSize is NULL or Buffer Size is not NULL but Buffer is NULL.
|
||||
@retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
|
||||
@retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
|
||||
BufferSize has been updated with the size needed to complete
|
||||
the request.
|
||||
@retval Others Unexpected error happened.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootGetBootFile (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private,
|
||||
IN BOOLEAN HeaderOnly,
|
||||
IN OUT UINTN *BufferSize,
|
||||
OUT UINT8 *Buffer
|
||||
);
|
||||
|
||||
/**
|
||||
Clean up all cached data.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootFreeCacheList (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,180 @@
|
|||
/** @file
|
||||
Implementation of EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL protocol.
|
||||
|
||||
Copyright (c) 2015, 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 that 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 "HttpBootDxe.h"
|
||||
|
||||
///
|
||||
/// Component Name Protocol instance
|
||||
///
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED
|
||||
EFI_COMPONENT_NAME_PROTOCOL gHttpBootDxeComponentName = {
|
||||
(EFI_COMPONENT_NAME_GET_DRIVER_NAME) HttpBootDxeComponentNameGetDriverName,
|
||||
(EFI_COMPONENT_NAME_GET_CONTROLLER_NAME)HttpBootDxeComponentNameGetControllerName,
|
||||
"eng"
|
||||
};
|
||||
|
||||
///
|
||||
/// Component Name 2 Protocol instance
|
||||
///
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED
|
||||
EFI_COMPONENT_NAME2_PROTOCOL gHttpBootDxeComponentName2 = {
|
||||
HttpBootDxeComponentNameGetDriverName,
|
||||
HttpBootDxeComponentNameGetControllerName,
|
||||
"en"
|
||||
};
|
||||
|
||||
///
|
||||
/// Table of driver names
|
||||
///
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED
|
||||
EFI_UNICODE_STRING_TABLE mHttpBootDxeDriverNameTable[] = {
|
||||
{ "eng;en", (CHAR16 *)L"UEFI HTTP Boot Driver" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
///
|
||||
/// Table of controller names
|
||||
///
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED
|
||||
EFI_UNICODE_STRING_TABLE mHttpBootDxeControllerNameTable[] = {
|
||||
{ "eng;en", (CHAR16 *)L"UEFI Http Boot Controller" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user-readable name of the EFI Driver.
|
||||
|
||||
@param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
@param Language A pointer to a three-character ISO 639-2 language identifier.
|
||||
This is the language of the driver name that that the caller
|
||||
is requesting, and it must match one of the languages specified
|
||||
in SupportedLanguages. The number of languages supported by a
|
||||
driver is up to the driver writer.
|
||||
@param DriverName A pointer to the Unicode string to return. This Unicode string
|
||||
is the name of the driver specified by This in the language
|
||||
specified by Language.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the Driver specified by This
|
||||
and the language specified by Language was returned
|
||||
in DriverName.
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
@retval EFI_INVALID_PARAMETER DriverName is NULL.
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support the
|
||||
language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootDxeComponentNameGetDriverName (
|
||||
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **DriverName
|
||||
)
|
||||
{
|
||||
return LookupUnicodeString2 (
|
||||
Language,
|
||||
This->SupportedLanguages,
|
||||
mHttpBootDxeDriverNameTable,
|
||||
DriverName,
|
||||
(BOOLEAN) (This != &gHttpBootDxeComponentName2)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user readable name of the controller
|
||||
that is being managed by an EFI Driver.
|
||||
|
||||
@param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
@param ControllerHandle The handle of a controller that the driver specified by
|
||||
This is managing. This handle specifies the controller
|
||||
whose name is to be returned.
|
||||
@param ChildHandle The handle of the child controller to retrieve the name
|
||||
of. This is an optional parameter that may be NULL. It
|
||||
will be NULL for device drivers. It will also be NULL
|
||||
for a bus drivers that wish to retrieve the name of the
|
||||
bus controller. It will not be NULL for a bus driver
|
||||
that wishes to retrieve the name of a child controller.
|
||||
@param Language A pointer to a three character ISO 639-2 language
|
||||
identifier. This is the language of the controller name
|
||||
that the caller is requesting, and it must match one
|
||||
of the languages specified in SupportedLanguages. The
|
||||
number of languages supported by a driver is up to the
|
||||
driver writer.
|
||||
@param ControllerName A pointer to the Unicode string to return. This Unicode
|
||||
string is the name of the controller specified by
|
||||
ControllerHandle and ChildHandle in the language specified
|
||||
by Language, from the point of view of the driver specified
|
||||
by This.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the user-readable name in the
|
||||
language specified by Language for the driver
|
||||
specified by This was returned in DriverName.
|
||||
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
|
||||
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
|
||||
@retval EFI_UNSUPPORTED The driver specified by This is not currently managing
|
||||
the controller specified by ControllerHandle and
|
||||
ChildHandle.
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support the
|
||||
language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootDxeComponentNameGetControllerName (
|
||||
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_HANDLE ChildHandle OPTIONAL,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **ControllerName
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_HANDLE NicHandle;
|
||||
UINT32 *Id;
|
||||
|
||||
if (ControllerHandle == NULL || ChildHandle != NULL) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
NicHandle = HttpBootGetNicByIp4Children (ControllerHandle);
|
||||
if (NicHandle == NULL) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// Try to retrieve the private data by caller ID GUID.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
NicHandle,
|
||||
&gEfiCallerIdGuid,
|
||||
(VOID **) &Id,
|
||||
NULL,
|
||||
NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
return LookupUnicodeString2 (
|
||||
Language,
|
||||
This->SupportedLanguages,
|
||||
mHttpBootDxeControllerNameTable,
|
||||
ControllerName,
|
||||
(BOOLEAN)(This != &gHttpBootDxeComponentName2)
|
||||
);
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/** @file
|
||||
Declaration of HTTP boot driver's EFI_COMPONENT_NAME_PROTOCOL and
|
||||
EFI_COMPONENT_NAME2_PROTOCOL function.
|
||||
|
||||
Copyright (c) 2015, 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 that 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.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __EFI_UEFI_HTTP_BOOT_COM_NAME_H__
|
||||
#define __EFI_UEFI_HTTP_BOOT_COM_NAME_H__
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user-readable name of the EFI Driver.
|
||||
|
||||
@param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
@param Language A pointer to a three-character ISO 639-2 language identifier.
|
||||
This is the language of the driver name that that the caller
|
||||
is requesting, and it must match one of the languages specified
|
||||
in SupportedLanguages. The number of languages supported by a
|
||||
driver is up to the driver writer.
|
||||
@param DriverName A pointer to the Unicode string to return. This Unicode string
|
||||
is the name of the driver specified by This in the language
|
||||
specified by Language.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the Driver specified by This
|
||||
and the language specified by Language was returned
|
||||
in DriverName.
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
@retval EFI_INVALID_PARAMETER DriverName is NULL.
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support the
|
||||
language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootDxeComponentNameGetDriverName (
|
||||
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **DriverName
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user readable name of the controller
|
||||
that is being managed by an EFI Driver.
|
||||
|
||||
@param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
@param ControllerHandle The handle of a controller that the driver specified by
|
||||
This is managing. This handle specifies the controller
|
||||
whose name is to be returned.
|
||||
@param ChildHandle The handle of the child controller to retrieve the name
|
||||
of. This is an optional parameter that may be NULL. It
|
||||
will be NULL for device drivers. It will also be NULL
|
||||
for a bus drivers that wish to retrieve the name of the
|
||||
bus controller. It will not be NULL for a bus driver
|
||||
that wishes to retrieve the name of a child controller.
|
||||
@param Language A pointer to a three character ISO 639-2 language
|
||||
identifier. This is the language of the controller name
|
||||
that the caller is requesting, and it must match one
|
||||
of the languages specified in SupportedLanguages. The
|
||||
number of languages supported by a driver is up to the
|
||||
driver writer.
|
||||
@param ControllerName A pointer to the Unicode string to return. This Unicode
|
||||
string is the name of the controller specified by
|
||||
ControllerHandle and ChildHandle in the language specified
|
||||
by Language, from the point of view of the driver specified
|
||||
by This.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the user-readable name in the
|
||||
language specified by Language for the driver
|
||||
specified by This was returned in DriverName.
|
||||
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
|
||||
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
|
||||
@retval EFI_UNSUPPORTED The driver specified by This is not currently managing
|
||||
the controller specified by ControllerHandle and
|
||||
ChildHandle.
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support the
|
||||
language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootDxeComponentNameGetControllerName (
|
||||
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_HANDLE ChildHandle OPTIONAL,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **ControllerName
|
||||
);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,829 @@
|
|||
/** @file
|
||||
Functions implementation related with DHCPv4 for HTTP boot driver.
|
||||
|
||||
Copyright (c) 2015, 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 that 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 "HttpBootDxe.h"
|
||||
|
||||
//
|
||||
// This is a map from the interested DHCP4 option tags' index to the tag value.
|
||||
//
|
||||
UINT8 mInterestedDhcp4Tags[HTTP_BOOT_DHCP4_TAG_INDEX_MAX] = {
|
||||
HTTP_BOOT_DHCP4_TAG_BOOTFILE_LEN,
|
||||
HTTP_BOOT_DHCP4_TAG_OVERLOAD,
|
||||
HTTP_BOOT_DHCP4_TAG_MSG_TYPE,
|
||||
HTTP_BOOT_DHCP4_TAG_SERVER_ID,
|
||||
HTTP_BOOT_DHCP4_TAG_CLASS_ID,
|
||||
HTTP_BOOT_DHCP4_TAG_BOOTFILE,
|
||||
HTTP_BOOT_DHCP4_TAG_DNS_SERVER
|
||||
};
|
||||
|
||||
//
|
||||
// There are 4 times retries with the value of 4, 8, 16 and 32, refers to UEFI 2.5 spec.
|
||||
//
|
||||
UINT32 mHttpDhcpTimeout[4] = {4, 8, 16, 32};
|
||||
|
||||
/**
|
||||
Build the options buffer for the DHCPv4 request packet.
|
||||
|
||||
@param[in] Private Pointer to HTTP boot driver private data.
|
||||
@param[out] OptList Pointer to the option pointer array.
|
||||
@param[in] Buffer Pointer to the buffer to contain the option list.
|
||||
|
||||
@return Index The count of the built-in options.
|
||||
|
||||
**/
|
||||
UINT32
|
||||
HttpBootBuildDhcp4Options (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private,
|
||||
OUT EFI_DHCP4_PACKET_OPTION **OptList,
|
||||
IN UINT8 *Buffer
|
||||
)
|
||||
{
|
||||
HTTP_BOOT_DHCP4_OPTION_ENTRY OptEnt;
|
||||
UINT16 Value;
|
||||
UINT32 Index;
|
||||
|
||||
Index = 0;
|
||||
OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Buffer;
|
||||
|
||||
//
|
||||
// Append parameter request list option.
|
||||
//
|
||||
OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_PARA_LIST;
|
||||
OptList[Index]->Length = 27;
|
||||
OptEnt.Para = (HTTP_BOOT_DHCP4_OPTION_PARA *) OptList[Index]->Data;
|
||||
OptEnt.Para->ParaList[0] = HTTP_BOOT_DHCP4_TAG_NETMASK;
|
||||
OptEnt.Para->ParaList[1] = HTTP_BOOT_DHCP4_TAG_TIME_OFFSET;
|
||||
OptEnt.Para->ParaList[2] = HTTP_BOOT_DHCP4_TAG_ROUTER;
|
||||
OptEnt.Para->ParaList[3] = HTTP_BOOT_DHCP4_TAG_TIME_SERVER;
|
||||
OptEnt.Para->ParaList[4] = HTTP_BOOT_DHCP4_TAG_NAME_SERVER;
|
||||
OptEnt.Para->ParaList[5] = HTTP_BOOT_DHCP4_TAG_DNS_SERVER;
|
||||
OptEnt.Para->ParaList[6] = HTTP_BOOT_DHCP4_TAG_HOSTNAME;
|
||||
OptEnt.Para->ParaList[7] = HTTP_BOOT_DHCP4_TAG_BOOTFILE_LEN;
|
||||
OptEnt.Para->ParaList[8] = HTTP_BOOT_DHCP4_TAG_DOMAINNAME;
|
||||
OptEnt.Para->ParaList[9] = HTTP_BOOT_DHCP4_TAG_ROOTPATH;
|
||||
OptEnt.Para->ParaList[10] = HTTP_BOOT_DHCP4_TAG_EXTEND_PATH;
|
||||
OptEnt.Para->ParaList[11] = HTTP_BOOT_DHCP4_TAG_EMTU;
|
||||
OptEnt.Para->ParaList[12] = HTTP_BOOT_DHCP4_TAG_TTL;
|
||||
OptEnt.Para->ParaList[13] = HTTP_BOOT_DHCP4_TAG_BROADCAST;
|
||||
OptEnt.Para->ParaList[14] = HTTP_BOOT_DHCP4_TAG_NIS_DOMAIN;
|
||||
OptEnt.Para->ParaList[15] = HTTP_BOOT_DHCP4_TAG_NIS_SERVER;
|
||||
OptEnt.Para->ParaList[16] = HTTP_BOOT_DHCP4_TAG_NTP_SERVER;
|
||||
OptEnt.Para->ParaList[17] = HTTP_BOOT_DHCP4_TAG_VENDOR;
|
||||
OptEnt.Para->ParaList[18] = HTTP_BOOT_DHCP4_TAG_REQUEST_IP;
|
||||
OptEnt.Para->ParaList[19] = HTTP_BOOT_DHCP4_TAG_LEASE;
|
||||
OptEnt.Para->ParaList[20] = HTTP_BOOT_DHCP4_TAG_SERVER_ID;
|
||||
OptEnt.Para->ParaList[21] = HTTP_BOOT_DHCP4_TAG_T1;
|
||||
OptEnt.Para->ParaList[22] = HTTP_BOOT_DHCP4_TAG_T2;
|
||||
OptEnt.Para->ParaList[23] = HTTP_BOOT_DHCP4_TAG_CLASS_ID;
|
||||
OptEnt.Para->ParaList[25] = HTTP_BOOT_DHCP4_TAG_BOOTFILE;
|
||||
OptEnt.Para->ParaList[26] = HTTP_BOOT_DHCP4_TAG_UUID;
|
||||
Index++;
|
||||
OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
|
||||
|
||||
//
|
||||
// Append UUID/Guid-based client identifier option
|
||||
//
|
||||
OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_UUID;
|
||||
OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_UUID);
|
||||
OptEnt.Uuid = (HTTP_BOOT_DHCP4_OPTION_UUID *) OptList[Index]->Data;
|
||||
OptEnt.Uuid->Type = 0;
|
||||
if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) OptEnt.Uuid->Guid))) {
|
||||
//
|
||||
// Zero the Guid to indicate NOT programable if failed to get system Guid.
|
||||
//
|
||||
ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));
|
||||
}
|
||||
Index++;
|
||||
OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
|
||||
|
||||
//
|
||||
// Append client network device interface option
|
||||
//
|
||||
OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_UNDI;
|
||||
OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_UNDI);
|
||||
OptEnt.Undi = (HTTP_BOOT_DHCP4_OPTION_UNDI *) OptList[Index]->Data;
|
||||
|
||||
if (Private->Nii != NULL) {
|
||||
OptEnt.Undi->Type = Private->Nii->Type;
|
||||
OptEnt.Undi->MajorVer = Private->Nii->MajorVer;
|
||||
OptEnt.Undi->MinorVer = Private->Nii->MinorVer;
|
||||
} else {
|
||||
OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;
|
||||
OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;
|
||||
OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;
|
||||
}
|
||||
|
||||
Index++;
|
||||
OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
|
||||
|
||||
//
|
||||
// Append client system architecture option
|
||||
//
|
||||
OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_ARCH;
|
||||
OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_ARCH);
|
||||
OptEnt.Arch = (HTTP_BOOT_DHCP4_OPTION_ARCH *) OptList[Index]->Data;
|
||||
Value = HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE);
|
||||
CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));
|
||||
Index++;
|
||||
OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
|
||||
|
||||
//
|
||||
// Append vendor class identify option
|
||||
//
|
||||
OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_CLASS_ID;
|
||||
OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_CLID);
|
||||
OptEnt.Clid = (HTTP_BOOT_DHCP4_OPTION_CLID *) OptList[Index]->Data;
|
||||
CopyMem (
|
||||
OptEnt.Clid,
|
||||
DEFAULT_CLASS_ID_DATA,
|
||||
sizeof (HTTP_BOOT_DHCP4_OPTION_CLID)
|
||||
);
|
||||
HttpBootUintnToAscDecWithFormat (
|
||||
EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE,
|
||||
OptEnt.Clid->ArchitectureType,
|
||||
sizeof (OptEnt.Clid->ArchitectureType)
|
||||
);
|
||||
|
||||
if (Private->Nii != NULL) {
|
||||
CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));
|
||||
HttpBootUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));
|
||||
HttpBootUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));
|
||||
}
|
||||
|
||||
Index++;
|
||||
|
||||
return Index;
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
|
||||
**/
|
||||
EFI_DHCP4_PACKET_OPTION *
|
||||
HttpBootParseDhcp4Options (
|
||||
IN UINT8 *Buffer,
|
||||
IN UINT32 Length,
|
||||
IN UINT8 OptTag
|
||||
)
|
||||
{
|
||||
EFI_DHCP4_PACKET_OPTION *Option;
|
||||
UINT32 Offset;
|
||||
|
||||
Option = (EFI_DHCP4_PACKET_OPTION *) Buffer;
|
||||
Offset = 0;
|
||||
|
||||
while (Offset < Length && Option->OpCode != HTTP_BOOT_DHCP4_TAG_EOP) {
|
||||
|
||||
if (Option->OpCode == OptTag) {
|
||||
//
|
||||
// Found the required option.
|
||||
//
|
||||
return Option;
|
||||
}
|
||||
|
||||
//
|
||||
// Skip the current option to the next.
|
||||
//
|
||||
if (Option->OpCode == HTTP_BOOT_DHCP4_TAG_PAD) {
|
||||
Offset++;
|
||||
} else {
|
||||
Offset += Option->Length + 2;
|
||||
}
|
||||
|
||||
Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootCacheDhcp4Packet (
|
||||
IN EFI_DHCP4_PACKET *Dst,
|
||||
IN EFI_DHCP4_PACKET *Src
|
||||
)
|
||||
{
|
||||
ASSERT (Dst->Size >= Src->Length);
|
||||
|
||||
CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);
|
||||
Dst->Length = Src->Length;
|
||||
}
|
||||
|
||||
/**
|
||||
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 an invalid packet.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootParseDhcp4Packet (
|
||||
IN HTTP_BOOT_DHCP4_PACKET_CACHE *Cache4
|
||||
)
|
||||
{
|
||||
EFI_DHCP4_PACKET *Offer;
|
||||
EFI_DHCP4_PACKET_OPTION **Options;
|
||||
UINTN Index;
|
||||
EFI_DHCP4_PACKET_OPTION *Option;
|
||||
BOOLEAN IsProxyOffer;
|
||||
BOOLEAN IsHttpOffer;
|
||||
BOOLEAN IsDnsOffer;
|
||||
BOOLEAN IpExpressedUri;
|
||||
UINT8 *Ptr8;
|
||||
EFI_STATUS Status;
|
||||
HTTP_BOOT_OFFER_TYPE OfferType;
|
||||
EFI_IPv4_ADDRESS IpAddr;
|
||||
|
||||
IsDnsOffer = FALSE;
|
||||
IpExpressedUri = FALSE;
|
||||
IsProxyOffer = FALSE;
|
||||
IsHttpOffer = FALSE;
|
||||
|
||||
ZeroMem (Cache4->OptList, sizeof (Cache4->OptList));
|
||||
|
||||
Offer = &Cache4->Packet.Offer;
|
||||
Options = Cache4->OptList;
|
||||
|
||||
//
|
||||
// Parse DHCPv4 options in this offer, and store the pointers.
|
||||
// First, try to parse DHCPv4 options from the DHCP optional parameters field.
|
||||
//
|
||||
for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {
|
||||
Options[Index] = HttpBootParseDhcp4Options (
|
||||
Offer->Dhcp4.Option,
|
||||
GET_OPTION_BUFFER_LEN (Offer),
|
||||
mInterestedDhcp4Tags[Index]
|
||||
);
|
||||
}
|
||||
//
|
||||
// Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.
|
||||
// If yes, try to parse options from the BootFileName field, then ServerName field.
|
||||
//
|
||||
Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_OVERLOAD];
|
||||
if (Option != NULL) {
|
||||
if ((Option->Data[0] & HTTP_BOOT_DHCP4_OVERLOAD_FILE) != 0) {
|
||||
for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {
|
||||
if (Options[Index] == NULL) {
|
||||
Options[Index] = HttpBootParseDhcp4Options (
|
||||
(UINT8 *) Offer->Dhcp4.Header.BootFileName,
|
||||
sizeof (Offer->Dhcp4.Header.BootFileName),
|
||||
mInterestedDhcp4Tags[Index]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((Option->Data[0] & HTTP_BOOT_DHCP4_OVERLOAD_SERVER_NAME) != 0) {
|
||||
for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {
|
||||
if (Options[Index] == NULL) {
|
||||
Options[Index] = HttpBootParseDhcp4Options (
|
||||
(UINT8 *) Offer->Dhcp4.Header.ServerName,
|
||||
sizeof (Offer->Dhcp4.Header.ServerName),
|
||||
mInterestedDhcp4Tags[Index]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// The offer with "yiaddr" is a proxy offer.
|
||||
//
|
||||
if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {
|
||||
IsProxyOffer = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// The offer with "HttpClient" is a Http offer.
|
||||
//
|
||||
Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_CLASS_ID];
|
||||
if ((Option != NULL) && (Option->Length >= 9) &&
|
||||
(CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {
|
||||
IsHttpOffer = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// The offer with Domain Server is a DNS offer.
|
||||
//
|
||||
Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER];
|
||||
if (Option != NULL) {
|
||||
IsDnsOffer = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse boot file name:
|
||||
// Boot URI information is provided thru 'file' field in DHCP Header or option 67.
|
||||
// According to RFC 2132, boot file name should be read from DHCP option 67 (bootfile name) if present.
|
||||
// Otherwise, read from boot file field in DHCP header.
|
||||
//
|
||||
if (Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
|
||||
//
|
||||
// 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 = (UINT8*)&Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];
|
||||
Ptr8 += Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Length;
|
||||
if (*(Ptr8 - 1) != '\0') {
|
||||
*Ptr8 = '\0';
|
||||
}
|
||||
} else if (Offer->Dhcp4.Header.BootFileName[0] != 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 destroy the serverhostname.
|
||||
//
|
||||
Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *)
|
||||
(&Offer->Dhcp4.Header.BootFileName[0] -
|
||||
OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));
|
||||
}
|
||||
|
||||
//
|
||||
// Http offer must have a boot URI.
|
||||
//
|
||||
if (IsHttpOffer && Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Try to retrieve the IP of HTTP server from URI.
|
||||
//
|
||||
if (IsHttpOffer) {
|
||||
Status = HttpParseUrl (
|
||||
(CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data,
|
||||
(UINT32) AsciiStrLen ((CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data),
|
||||
FALSE,
|
||||
&Cache4->UriParser
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
Status = HttpUrlGetIp4 (
|
||||
(CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data,
|
||||
Cache4->UriParser,
|
||||
&IpAddr
|
||||
);
|
||||
IpExpressedUri = !EFI_ERROR (Status);
|
||||
}
|
||||
|
||||
//
|
||||
// Determine offer type of the DHCPv4 packet.
|
||||
//
|
||||
if (IsHttpOffer) {
|
||||
if (IpExpressedUri) {
|
||||
OfferType = IsProxyOffer ? HttpOfferTypeProxyIpUri : HttpOfferTypeDhcpIpUri;
|
||||
} else {
|
||||
if (!IsProxyOffer) {
|
||||
OfferType = IsDnsOffer ? HttpOfferTypeDhcpNameUriDns : HttpOfferTypeDhcpNameUri;
|
||||
} else {
|
||||
OfferType = HttpOfferTypeProxyNameUri;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!IsProxyOffer) {
|
||||
OfferType = IsDnsOffer ? HttpOfferTypeDhcpDns : HttpOfferTypeDhcpOnly;
|
||||
} else {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
Cache4->OfferType = OfferType;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.
|
||||
|
||||
@param[in] Private Pointer to HTTP boot driver private data.
|
||||
@param[in] RcvdOffer Pointer to the received offer packet.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootCacheDhcp4Offer (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private,
|
||||
IN EFI_DHCP4_PACKET *RcvdOffer
|
||||
)
|
||||
{
|
||||
HTTP_BOOT_DHCP4_PACKET_CACHE *Cache4;
|
||||
EFI_DHCP4_PACKET *Offer;
|
||||
HTTP_BOOT_OFFER_TYPE OfferType;
|
||||
|
||||
ASSERT (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM);
|
||||
Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;
|
||||
Offer = &Cache4->Packet.Offer;
|
||||
|
||||
//
|
||||
// Cache the content of DHCPv4 packet firstly.
|
||||
//
|
||||
HttpBootCacheDhcp4Packet (Offer, RcvdOffer);
|
||||
|
||||
//
|
||||
// Validate the DHCPv4 packet, and parse the options and offer type.
|
||||
//
|
||||
if (EFI_ERROR (HttpBootParseDhcp4Packet (Cache4))) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
|
||||
//
|
||||
OfferType = Cache4->OfferType;
|
||||
ASSERT (OfferType < HttpOfferTypeMax);
|
||||
ASSERT (Private->OfferCount[OfferType] < HTTP_BOOT_OFFER_MAX_NUM);
|
||||
Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
|
||||
Private->OfferCount[OfferType]++;
|
||||
Private->OfferNum++;
|
||||
}
|
||||
|
||||
/**
|
||||
Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.
|
||||
|
||||
@param[in] Private Pointer to HTTP boot driver private data.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootSelectDhcp4Offer (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
Private->SelectIndex = 0;
|
||||
Private->SelectProxyType = HttpOfferTypeMax;
|
||||
|
||||
//
|
||||
// Priority1: HttpOfferTypeDhcpIpUri
|
||||
// Priority2: HttpOfferTypeDhcpNameUriDns
|
||||
// Priority3: HttpOfferTypeDhcpOnly + HttpOfferTypeProxyIpUri
|
||||
// Priority4: HttpOfferTypeDhcpDns + HttpOfferTypeProxyIpUri
|
||||
// Priority5: HttpOfferTypeDhcpDns + HttpOfferTypeProxyNameUri
|
||||
// Priority6: HttpOfferTypeDhcpDns + HttpOfferTypeDhcpNameUri
|
||||
//
|
||||
if (Private->OfferCount[HttpOfferTypeDhcpIpUri] > 0) {
|
||||
|
||||
Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUri][0] + 1;
|
||||
|
||||
} else if (Private->OfferCount[HttpOfferTypeDhcpNameUriDns] > 0) {
|
||||
|
||||
Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpNameUriDns][0] + 1;
|
||||
|
||||
} else if (Private->OfferCount[HttpOfferTypeDhcpOnly] > 0 &&
|
||||
Private->OfferCount[HttpOfferTypeProxyIpUri] > 0) {
|
||||
|
||||
Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpOnly][0] + 1;
|
||||
Private->SelectProxyType = HttpOfferTypeProxyIpUri;
|
||||
|
||||
} else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&
|
||||
Private->OfferCount[HttpOfferTypeProxyIpUri] > 0) {
|
||||
|
||||
Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;
|
||||
Private->SelectProxyType = HttpOfferTypeProxyIpUri;
|
||||
|
||||
} else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&
|
||||
Private->OfferCount[HttpOfferTypeProxyNameUri] > 0) {
|
||||
|
||||
Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;
|
||||
Private->SelectProxyType = HttpOfferTypeProxyNameUri;
|
||||
|
||||
} else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&
|
||||
Private->OfferCount[HttpOfferTypeDhcpNameUri] > 0) {
|
||||
|
||||
Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;
|
||||
Private->SelectProxyType = HttpOfferTypeDhcpNameUri;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootDhcp4CallBack (
|
||||
IN EFI_DHCP4_PROTOCOL *This,
|
||||
IN VOID *Context,
|
||||
IN EFI_DHCP4_STATE CurrentState,
|
||||
IN EFI_DHCP4_EVENT Dhcp4Event,
|
||||
IN EFI_DHCP4_PACKET *Packet OPTIONAL,
|
||||
OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL
|
||||
)
|
||||
{
|
||||
HTTP_BOOT_PRIVATE_DATA *Private;
|
||||
EFI_DHCP4_PACKET_OPTION *MaxMsgSize;
|
||||
UINT16 Value;
|
||||
EFI_STATUS Status;
|
||||
|
||||
if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Private = (HTTP_BOOT_PRIVATE_DATA *) Context;
|
||||
|
||||
//
|
||||
// Override the Maximum DHCP Message Size.
|
||||
//
|
||||
MaxMsgSize = HttpBootParseDhcp4Options (
|
||||
Packet->Dhcp4.Option,
|
||||
GET_OPTION_BUFFER_LEN (Packet),
|
||||
HTTP_BOOT_DHCP4_TAG_MAXMSG
|
||||
);
|
||||
if (MaxMsgSize != NULL) {
|
||||
Value = HTONS (HTTP_BOOT_DHCP4_PACKET_MAX_SIZE);
|
||||
CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));
|
||||
}
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
switch (Dhcp4Event) {
|
||||
case Dhcp4RcvdOffer:
|
||||
Status = EFI_NOT_READY;
|
||||
if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) {
|
||||
//
|
||||
// Cache the DHCPv4 offers to OfferBuffer[] for select later, and record
|
||||
// the OfferIndex and OfferCount.
|
||||
//
|
||||
HttpBootCacheDhcp4Offer (Private, Packet);
|
||||
}
|
||||
break;
|
||||
|
||||
case Dhcp4SelectOffer:
|
||||
//
|
||||
// Select offer according to the priority in UEFI spec, and record the SelectIndex
|
||||
// and SelectProxyType.
|
||||
//
|
||||
HttpBootSelectDhcp4Offer (Private);
|
||||
|
||||
if (Private->SelectIndex == 0) {
|
||||
Status = EFI_ABORTED;
|
||||
} else {
|
||||
*NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
This function will register the IPv4 gateway address to the network device.
|
||||
|
||||
@param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
|
||||
|
||||
@retval EFI_SUCCESS The new IP configuration has been configured successfully.
|
||||
@retval Others Failed to configure the address.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootRegisterIp4Gateway (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
|
||||
|
||||
ASSERT (!Private->UsingIpv6);
|
||||
|
||||
Ip4Config2 = Private->Ip4Config2;
|
||||
|
||||
//
|
||||
// Configure the gateway if valid.
|
||||
//
|
||||
if (!EFI_IP4_EQUAL (&Private->GatewayIp, &mZeroIp4Addr)) {
|
||||
Status = Ip4Config2->SetData (
|
||||
Ip4Config2,
|
||||
Ip4Config2DataTypeGateway,
|
||||
sizeof (EFI_IPv4_ADDRESS),
|
||||
&Private->GatewayIp
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
This function will register the default DNS addresses to the network device.
|
||||
|
||||
@param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
|
||||
@param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.
|
||||
@param[in] DnsServerData Point a list of DNS server address in an array
|
||||
of EFI_IPv4_ADDRESS instances.
|
||||
|
||||
@retval EFI_SUCCESS The DNS configuration has been configured successfully.
|
||||
@retval Others Failed to configure the address.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootRegisterIp4Dns (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private,
|
||||
IN UINTN DataLength,
|
||||
IN VOID *DnsServerData
|
||||
)
|
||||
{
|
||||
EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
|
||||
|
||||
ASSERT (!Private->UsingIpv6);
|
||||
|
||||
Ip4Config2 = Private->Ip4Config2;
|
||||
|
||||
return Ip4Config2->SetData (
|
||||
Ip4Config2,
|
||||
Ip4Config2DataTypeDnsServer,
|
||||
DataLength,
|
||||
DnsServerData
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This function will switch the IP4 configuration policy to Static.
|
||||
|
||||
@param[in] Private Pointer to HTTP boot driver private data.
|
||||
|
||||
@retval EFI_SUCCESS The policy is already configured to static.
|
||||
@retval Others Other error as indicated..
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootSetIpPolicy (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
EFI_IP4_CONFIG2_POLICY Policy;
|
||||
EFI_STATUS Status;
|
||||
EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
|
||||
UINTN DataSize;
|
||||
|
||||
Ip4Config2 = Private->Ip4Config2;
|
||||
|
||||
DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
|
||||
Status = Ip4Config2->GetData (
|
||||
Ip4Config2,
|
||||
Ip4Config2DataTypePolicy,
|
||||
&DataSize,
|
||||
&Policy
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (Policy != Ip4Config2PolicyStatic) {
|
||||
Policy = Ip4Config2PolicyStatic;
|
||||
Status= Ip4Config2->SetData (
|
||||
Ip4Config2,
|
||||
Ip4Config2DataTypePolicy,
|
||||
sizeof (EFI_IP4_CONFIG2_POLICY),
|
||||
&Policy
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other Http boot information.
|
||||
|
||||
@param[in] Private Pointer to HTTP boot driver private data.
|
||||
|
||||
@retval EFI_SUCCESS The D.O.R.A process successfully finished.
|
||||
@retval Others Failed to finish the D.O.R.A process.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootDhcp4Dora (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
EFI_DHCP4_PROTOCOL *Dhcp4;
|
||||
UINT32 OptCount;
|
||||
EFI_DHCP4_PACKET_OPTION *OptList[HTTP_BOOT_DHCP4_OPTION_MAX_NUM];
|
||||
UINT8 Buffer[HTTP_BOOT_DHCP4_OPTION_MAX_SIZE];
|
||||
EFI_DHCP4_CONFIG_DATA Config;
|
||||
EFI_STATUS Status;
|
||||
EFI_DHCP4_MODE_DATA Mode;
|
||||
|
||||
Dhcp4 = Private->Dhcp4;
|
||||
ASSERT (Dhcp4 != NULL);
|
||||
|
||||
Status = HttpBootSetIpPolicy (Private);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Build option list for the request packet.
|
||||
//
|
||||
OptCount = HttpBootBuildDhcp4Options (Private, OptList, Buffer);
|
||||
ASSERT (OptCount > 0);
|
||||
|
||||
ZeroMem (&Config, sizeof(Config));
|
||||
Config.OptionCount = OptCount;
|
||||
Config.OptionList = OptList;
|
||||
Config.Dhcp4Callback = HttpBootDhcp4CallBack;
|
||||
Config.CallbackContext = Private;
|
||||
Config.DiscoverTryCount = HTTP_BOOT_DHCP_RETRIES;
|
||||
Config.DiscoverTimeout = mHttpDhcpTimeout;
|
||||
|
||||
//
|
||||
// Configure the DHCPv4 instance for HTTP boot.
|
||||
//
|
||||
Status = Dhcp4->Configure (Dhcp4, &Config);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the record fields for DHCPv4 offer in private data.
|
||||
//
|
||||
Private->OfferNum = 0;
|
||||
ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
|
||||
ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
|
||||
|
||||
//
|
||||
// Start DHCPv4 D.O.R.A. process to acquire IPv4 address.
|
||||
//
|
||||
Status = Dhcp4->Start (Dhcp4, NULL);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the acquired IPv4 address and store them.
|
||||
//
|
||||
Status = Dhcp4->GetModeData (Dhcp4, &Mode);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
ASSERT (Mode.State == Dhcp4Bound);
|
||||
CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
|
||||
CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
|
||||
CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
|
||||
|
||||
Status = HttpBootRegisterIp4Gateway (Private);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
AsciiPrint ("\n Station IP address is ");
|
||||
HttpBootShowIp4Addr (&Private->StationIp.v4);
|
||||
AsciiPrint ("\n");
|
||||
|
||||
ON_EXIT:
|
||||
if (EFI_ERROR (Status)) {
|
||||
Dhcp4->Stop (Dhcp4);
|
||||
Dhcp4->Configure (Dhcp4, NULL);
|
||||
} else {
|
||||
ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
|
||||
Dhcp4->Configure (Dhcp4, &Config);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
/** @file
|
||||
Functions declaration related with DHCPv4 for HTTP boot driver.
|
||||
|
||||
Copyright (c) 2015, 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 that 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.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __EFI_UEFI_HTTP_BOOT_DHCP4_H__
|
||||
#define __EFI_UEFI_HTTP_BOOT_DHCP4_H__
|
||||
|
||||
#define HTTP_BOOT_DHCP4_OPTION_MAX_NUM 16
|
||||
#define HTTP_BOOT_DHCP4_OPTION_MAX_SIZE 312
|
||||
#define HTTP_BOOT_DHCP4_PACKET_MAX_SIZE 1472
|
||||
|
||||
#define HTTP_BOOT_DHCP4_OPCODE_REQUEST 1
|
||||
#define HTTP_BOOT_DHCP4_OPCODE_REPLY 2
|
||||
#define HTTP_BOOT_DHCP4_MSG_TYPE_REQUEST 3
|
||||
#define HTTP_BOOT_DHCP4_MAGIC 0x63538263 // network byte order
|
||||
|
||||
//
|
||||
// Dhcp Options
|
||||
//
|
||||
#define HTTP_BOOT_DHCP4_TAG_PAD 0 // Pad Option
|
||||
#define HTTP_BOOT_DHCP4_TAG_EOP 255 // End Option
|
||||
#define HTTP_BOOT_DHCP4_TAG_NETMASK 1 // Subnet Mask
|
||||
#define HTTP_BOOT_DHCP4_TAG_TIME_OFFSET 2 // Time Offset from UTC
|
||||
#define HTTP_BOOT_DHCP4_TAG_ROUTER 3 // Router option,
|
||||
#define HTTP_BOOT_DHCP4_TAG_TIME_SERVER 4 // Time Server
|
||||
#define HTTP_BOOT_DHCP4_TAG_NAME_SERVER 5 // Name Server
|
||||
#define HTTP_BOOT_DHCP4_TAG_DNS_SERVER 6 // Domain Name Server
|
||||
#define HTTP_BOOT_DHCP4_TAG_HOSTNAME 12 // Host Name
|
||||
#define HTTP_BOOT_DHCP4_TAG_BOOTFILE_LEN 13 // Boot File Size
|
||||
#define HTTP_BOOT_DHCP4_TAG_DUMP 14 // Merit Dump File
|
||||
#define HTTP_BOOT_DHCP4_TAG_DOMAINNAME 15 // Domain Name
|
||||
#define HTTP_BOOT_DHCP4_TAG_ROOTPATH 17 // Root path
|
||||
#define HTTP_BOOT_DHCP4_TAG_EXTEND_PATH 18 // Extensions Path
|
||||
#define HTTP_BOOT_DHCP4_TAG_EMTU 22 // Maximum Datagram Reassembly Size
|
||||
#define HTTP_BOOT_DHCP4_TAG_TTL 23 // Default IP Time-to-live
|
||||
#define HTTP_BOOT_DHCP4_TAG_BROADCAST 28 // Broadcast Address
|
||||
#define HTTP_BOOT_DHCP4_TAG_NIS_DOMAIN 40 // Network Information Service Domain
|
||||
#define HTTP_BOOT_DHCP4_TAG_NIS_SERVER 41 // Network Information Servers
|
||||
#define HTTP_BOOT_DHCP4_TAG_NTP_SERVER 42 // Network Time Protocol Servers
|
||||
#define HTTP_BOOT_DHCP4_TAG_VENDOR 43 // Vendor Specific Information
|
||||
#define HTTP_BOOT_DHCP4_TAG_REQUEST_IP 50 // Requested IP Address
|
||||
#define HTTP_BOOT_DHCP4_TAG_LEASE 51 // IP Address Lease Time
|
||||
#define HTTP_BOOT_DHCP4_TAG_OVERLOAD 52 // Option Overload
|
||||
#define HTTP_BOOT_DHCP4_TAG_MSG_TYPE 53 // DHCP Message Type
|
||||
#define HTTP_BOOT_DHCP4_TAG_SERVER_ID 54 // Server Identifier
|
||||
#define HTTP_BOOT_DHCP4_TAG_PARA_LIST 55 // Parameter Request List
|
||||
#define HTTP_BOOT_DHCP4_TAG_MAXMSG 57 // Maximum DHCP Message Size
|
||||
#define HTTP_BOOT_DHCP4_TAG_T1 58 // Renewal (T1) Time Value
|
||||
#define HTTP_BOOT_DHCP4_TAG_T2 59 // Rebinding (T2) Time Value
|
||||
#define HTTP_BOOT_DHCP4_TAG_CLASS_ID 60 // Vendor class identifier
|
||||
#define HTTP_BOOT_DHCP4_TAG_CLIENT_ID 61 // Client-identifier
|
||||
#define HTTP_BOOT_DHCP4_TAG_TFTP 66 // TFTP server name
|
||||
#define HTTP_BOOT_DHCP4_TAG_BOOTFILE 67 // Bootfile name
|
||||
#define HTTP_BOOT_DHCP4_TAG_ARCH 93
|
||||
#define HTTP_BOOT_DHCP4_TAG_UNDI 94
|
||||
#define HTTP_BOOT_DHCP4_TAG_UUID 97
|
||||
|
||||
#define HTTP_BOOT_DHCP4_OVERLOAD_FILE 1
|
||||
#define HTTP_BOOT_DHCP4_OVERLOAD_SERVER_NAME 2
|
||||
|
||||
///
|
||||
/// HTTP Tag definition that identifies the processor
|
||||
/// and programming environment of the client system.
|
||||
/// These identifiers are defined by IETF:
|
||||
/// http://www.ietf.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml
|
||||
///
|
||||
#if defined (MDE_CPU_IA32)
|
||||
#define EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE 0x000F
|
||||
#elif defined (MDE_CPU_X64)
|
||||
#define EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE 0x0010
|
||||
#elif defined (MDE_CPU_ARM)
|
||||
#define EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE 0x0012
|
||||
#elif defined (MDE_CPU_AARCH64)
|
||||
#define EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE 0x0013
|
||||
#endif
|
||||
|
||||
/// DHCP offer types among HTTP boot.
|
||||
/// Dhcp4 and Dhcp6 share this definition, and corresponding
|
||||
/// relatioinship is as follows:
|
||||
/// Dhcp4Discover <> Dhcp6Solicit
|
||||
/// Dhcp4Offer <> Dhcp6Advertise
|
||||
/// Dhcp4Request <> Dhcp6Request
|
||||
/// Dhcp4Ack <> DHcp6Reply
|
||||
///
|
||||
typedef enum {
|
||||
//
|
||||
// <IP address, IP expressed URI> or
|
||||
// <IP address, IP expressed URI, Name-server (will be ignored)>
|
||||
//
|
||||
HttpOfferTypeDhcpIpUri,
|
||||
//
|
||||
// <IP address, Domain-name expressed URI, Name-server>
|
||||
//
|
||||
HttpOfferTypeDhcpNameUriDns,
|
||||
//
|
||||
// <IP address, Name-server>
|
||||
//
|
||||
HttpOfferTypeDhcpDns,
|
||||
//
|
||||
// <IP address>
|
||||
//
|
||||
HttpOfferTypeDhcpOnly,
|
||||
//
|
||||
// <Domain-name expressed URI> or
|
||||
// <Domain-name expressed URI, Name-server (will be ignored)>
|
||||
//
|
||||
HttpOfferTypeProxyNameUri,
|
||||
//
|
||||
// <IP expressed URI> or
|
||||
// <IP expressed URI, Name-server (will be ignored)>
|
||||
//
|
||||
HttpOfferTypeProxyIpUri,
|
||||
//
|
||||
// <IP address, Domain-name expressed URI>
|
||||
//
|
||||
HttpOfferTypeDhcpNameUri,
|
||||
HttpOfferTypeMax
|
||||
} HTTP_BOOT_OFFER_TYPE;
|
||||
|
||||
#define HTTP_BOOT_DHCP_RETRIES 4
|
||||
#define HTTP_BOOT_OFFER_MAX_NUM 16
|
||||
|
||||
// The array index of the DHCP4 option tag interested
|
||||
//
|
||||
#define HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE_LEN 0
|
||||
#define HTTP_BOOT_DHCP4_TAG_INDEX_OVERLOAD 1
|
||||
#define HTTP_BOOT_DHCP4_TAG_INDEX_MSG_TYPE 2
|
||||
#define HTTP_BOOT_DHCP4_TAG_INDEX_SERVER_ID 3
|
||||
#define HTTP_BOOT_DHCP4_TAG_INDEX_CLASS_ID 4
|
||||
#define HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE 5
|
||||
#define HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER 6
|
||||
#define HTTP_BOOT_DHCP4_TAG_INDEX_MAX 7
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct {
|
||||
UINT8 ParaList[135];
|
||||
} HTTP_BOOT_DHCP4_OPTION_PARA;
|
||||
|
||||
typedef struct {
|
||||
UINT16 Size;
|
||||
} HTTP_BOOT_DHCP4_OPTION_MAX_MESG_SIZE;
|
||||
|
||||
typedef struct {
|
||||
UINT8 Type;
|
||||
UINT8 MajorVer;
|
||||
UINT8 MinorVer;
|
||||
} HTTP_BOOT_DHCP4_OPTION_UNDI;
|
||||
|
||||
typedef struct {
|
||||
UINT8 Type;
|
||||
} HTTP_BOOT_DHCP4_OPTION_MESG;
|
||||
|
||||
typedef struct {
|
||||
UINT16 Type;
|
||||
} HTTP_BOOT_DHCP4_OPTION_ARCH;
|
||||
|
||||
typedef struct {
|
||||
UINT8 ClassIdentifier[11];
|
||||
UINT8 ArchitecturePrefix[5];
|
||||
UINT8 ArchitectureType[5];
|
||||
UINT8 Lit3[1];
|
||||
UINT8 InterfaceName[4];
|
||||
UINT8 Lit4[1];
|
||||
UINT8 UndiMajor[3];
|
||||
UINT8 UndiMinor[3];
|
||||
} HTTP_BOOT_DHCP4_OPTION_CLID;
|
||||
|
||||
typedef struct {
|
||||
UINT8 Type;
|
||||
UINT8 Guid[16];
|
||||
} HTTP_BOOT_DHCP4_OPTION_UUID;
|
||||
|
||||
typedef struct {
|
||||
UINT16 Type;
|
||||
UINT16 Layer;
|
||||
} HTTP_BOOT_OPTION_BOOT_ITEM;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
typedef union {
|
||||
HTTP_BOOT_DHCP4_OPTION_PARA *Para;
|
||||
HTTP_BOOT_DHCP4_OPTION_UNDI *Undi;
|
||||
HTTP_BOOT_DHCP4_OPTION_ARCH *Arch;
|
||||
HTTP_BOOT_DHCP4_OPTION_CLID *Clid;
|
||||
HTTP_BOOT_DHCP4_OPTION_UUID *Uuid;
|
||||
HTTP_BOOT_DHCP4_OPTION_MESG *Mesg;
|
||||
HTTP_BOOT_DHCP4_OPTION_MAX_MESG_SIZE *MaxMesgSize;
|
||||
} HTTP_BOOT_DHCP4_OPTION_ENTRY;
|
||||
|
||||
#define GET_NEXT_DHCP_OPTION(Opt) \
|
||||
(EFI_DHCP4_PACKET_OPTION *) ((UINT8 *) (Opt) + \
|
||||
sizeof (EFI_DHCP4_PACKET_OPTION) + (Opt)->Length - 1)
|
||||
|
||||
#define GET_OPTION_BUFFER_LEN(Pkt) \
|
||||
((Pkt)->Length - sizeof (EFI_DHCP4_HEADER) - 4)
|
||||
|
||||
#define DEFAULT_CLASS_ID_DATA "HTTPClient:Arch:xxxxx:UNDI:003000"
|
||||
#define DEFAULT_UNDI_TYPE 1
|
||||
#define DEFAULT_UNDI_MAJOR 3
|
||||
#define DEFAULT_UNDI_MINOR 0
|
||||
|
||||
typedef struct {
|
||||
UINT32 Reserved;
|
||||
} HTTP_BOOT_VENDOR_OPTION;
|
||||
|
||||
typedef union {
|
||||
EFI_DHCP4_PACKET Offer;
|
||||
EFI_DHCP4_PACKET Ack;
|
||||
UINT8 Buffer[HTTP_BOOT_DHCP4_PACKET_MAX_SIZE];
|
||||
} HTTP_BOOT_DHCP4_PACKET;
|
||||
|
||||
typedef struct {
|
||||
//
|
||||
// URI component
|
||||
//
|
||||
CHAR8 *Scheme;
|
||||
CHAR8 *Authority;
|
||||
CHAR8 *Path;
|
||||
CHAR8 *Query;
|
||||
CHAR8 *Fragment; /// TODO: may not required in HTTP URL
|
||||
|
||||
CHAR8 *RegName; /// Point to somewhere in Authority
|
||||
BOOLEAN AddrIsOk;
|
||||
EFI_IP_ADDRESS Address;
|
||||
UINT16 Port;
|
||||
} HTTP_BOOT_URI_CONTENT;
|
||||
|
||||
typedef struct {
|
||||
HTTP_BOOT_DHCP4_PACKET Packet;
|
||||
HTTP_BOOT_OFFER_TYPE OfferType;
|
||||
VOID *UriParser;
|
||||
EFI_DHCP4_PACKET_OPTION *OptList[HTTP_BOOT_DHCP4_TAG_INDEX_MAX];
|
||||
} HTTP_BOOT_DHCP4_PACKET_CACHE;
|
||||
|
||||
/**
|
||||
Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other Http boot information.
|
||||
|
||||
@param[in] Private Pointer to HTTP_BOOT private data.
|
||||
|
||||
@retval EFI_SUCCESS The D.O.R.A process successfully finished.
|
||||
@retval Others Failed to finish the D.O.R.A process.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootDhcp4Dora (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
);
|
||||
|
||||
/**
|
||||
This function will register the default DNS addresses to the network device.
|
||||
|
||||
@param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
|
||||
@param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.
|
||||
@param[in] DnsServerData Point a list of DNS server address in an array
|
||||
of EFI_IPv4_ADDRESS instances.
|
||||
|
||||
@retval EFI_SUCCESS The DNS configuration has been configured successfully.
|
||||
@retval Others Failed to configure the address.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootRegisterIp4Dns (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private,
|
||||
IN UINTN DataLength,
|
||||
IN VOID *DnsServerData
|
||||
);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,559 @@
|
|||
/** @file
|
||||
Driver Binding functions implementation for UEFI HTTP boot.
|
||||
|
||||
Copyright (c) 2015, 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 that 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 "HttpBootDxe.h"
|
||||
|
||||
///
|
||||
/// Driver Binding Protocol instance
|
||||
///
|
||||
EFI_DRIVER_BINDING_PROTOCOL gHttpBootIp4DxeDriverBinding = {
|
||||
HttpBootIp4DxeDriverBindingSupported,
|
||||
HttpBootIp4DxeDriverBindingStart,
|
||||
HttpBootIp4DxeDriverBindingStop,
|
||||
HTTP_BOOT_DXE_VERSION,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
Destroy the HTTP child based on IPv4 stack.
|
||||
|
||||
@param[in] This Pointer to the EFI_DRIVER_BINDING_PROTOCOL.
|
||||
@param[in] Private Pointer to HTTP_BOOT_PRIVATE_DATA.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootDestroyIp4Children (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
ASSERT (This != NULL);
|
||||
ASSERT (Private != NULL);
|
||||
ASSERT (Private->UsingIpv6 == FALSE);
|
||||
|
||||
if (Private->Dhcp4Child != NULL) {
|
||||
gBS->CloseProtocol (
|
||||
Private->Dhcp4Child,
|
||||
&gEfiDhcp4ProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
Private->Controller
|
||||
);
|
||||
|
||||
NetLibDestroyServiceChild (
|
||||
Private->Controller,
|
||||
This->DriverBindingHandle,
|
||||
&gEfiDhcp4ServiceBindingProtocolGuid,
|
||||
Private->Dhcp4Child
|
||||
);
|
||||
}
|
||||
|
||||
if (Private->HttpCreated) {
|
||||
HttpIoDestroyIo (&Private->HttpIo);
|
||||
Private->HttpCreated = FALSE;
|
||||
}
|
||||
|
||||
gBS->CloseProtocol (
|
||||
Private->Controller,
|
||||
&gEfiCallerIdGuid,
|
||||
This->DriverBindingHandle,
|
||||
Private->ChildHandle
|
||||
);
|
||||
|
||||
gBS->UninstallMultipleProtocolInterfaces (
|
||||
Private->ChildHandle,
|
||||
&gEfiLoadFileProtocolGuid,
|
||||
&Private->LoadFile,
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
Private->DevicePath,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (Private->DevicePath != NULL) {
|
||||
FreePool (Private->DevicePath);
|
||||
Private->DevicePath = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Tests to see if this driver supports a given controller. If a child device is provided,
|
||||
it further tests to see if this driver supports creating a handle for the specified child device.
|
||||
|
||||
This function checks to see if the driver specified by This supports the device specified by
|
||||
ControllerHandle. Drivers will typically use the device path attached to
|
||||
ControllerHandle and/or the services from the bus I/O abstraction attached to
|
||||
ControllerHandle to determine if the driver supports ControllerHandle. This function
|
||||
may be called many times during platform initialization. In order to reduce boot times, the tests
|
||||
performed by this function must be very small, and take as little time as possible to execute. This
|
||||
function must not change the state of any hardware devices, and this function must be aware that the
|
||||
device specified by ControllerHandle may already be managed by the same driver or a
|
||||
different driver. This function must match its calls to AllocatePages() with FreePages(),
|
||||
AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
|
||||
Because ControllerHandle may have been previously started by the same driver, if a protocol is
|
||||
already in the opened state, then it must not be closed with CloseProtocol(). This is required
|
||||
to guarantee the state of ControllerHandle is not modified by this function.
|
||||
|
||||
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] ControllerHandle The handle of the controller to test. This handle
|
||||
must support a protocol interface that supplies
|
||||
an I/O abstraction to the driver.
|
||||
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
|
||||
parameter is ignored by device drivers, and is optional for bus
|
||||
drivers. For bus drivers, if this parameter is not NULL, then
|
||||
the bus driver must determine if the bus controller specified
|
||||
by ControllerHandle and the child controller specified
|
||||
by RemainingDevicePath are both supported by this
|
||||
bus driver.
|
||||
|
||||
@retval EFI_SUCCESS The device specified by ControllerHandle and
|
||||
RemainingDevicePath is supported by the driver specified by This.
|
||||
@retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is already being managed by the driver
|
||||
specified by This.
|
||||
@retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is already being managed by a different
|
||||
driver or an application that requires exclusive access.
|
||||
Currently not implemented.
|
||||
@retval EFI_UNSUPPORTED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is not supported by the driver specified by This.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootIp4DxeDriverBindingSupported (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// Try to open the DHCP4, HTTP4 and Device Path protocol.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDhcp4ServiceBindingProtocolGuid,
|
||||
NULL,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiHttpServiceBindingProtocolGuid,
|
||||
NULL,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
NULL,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Starts a device controller or a bus controller.
|
||||
|
||||
The Start() function is designed to be invoked from the EFI boot service ConnectController().
|
||||
As a result, much of the error checking on the parameters to Start() has been moved into this
|
||||
common boot service. It is legal to call Start() from other locations,
|
||||
but the following calling restrictions must be followed, or the system behavior will not be deterministic.
|
||||
1. ControllerHandle must be a valid EFI_HANDLE.
|
||||
2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
|
||||
EFI_DEVICE_PATH_PROTOCOL.
|
||||
3. Prior to calling Start(), the Supported() function for the driver specified by This must
|
||||
have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
|
||||
|
||||
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] ControllerHandle The handle of the controller to start. This handle
|
||||
must support a protocol interface that supplies
|
||||
an I/O abstraction to the driver.
|
||||
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
|
||||
parameter is ignored by device drivers, and is optional for bus
|
||||
drivers. For a bus driver, if this parameter is NULL, then handles
|
||||
for all the children of Controller are created by this driver.
|
||||
If this parameter is not NULL and the first Device Path Node is
|
||||
not the End of Device Path Node, then only the handle for the
|
||||
child device specified by the first Device Path Node of
|
||||
RemainingDevicePath is created by this driver.
|
||||
If the first Device Path Node of RemainingDevicePath is
|
||||
the End of Device Path Node, no child handle is created by this
|
||||
driver.
|
||||
|
||||
@retval EFI_SUCCESS The device was started.
|
||||
@retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
|
||||
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
|
||||
@retval Others The driver failded to start the device.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootIp4DxeDriverBindingStart (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
HTTP_BOOT_PRIVATE_DATA *Private;
|
||||
EFI_DEV_PATH *Node;
|
||||
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
||||
UINT32 *Id;
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiCallerIdGuid,
|
||||
(VOID **) &Id,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
return EFI_ALREADY_STARTED;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the private data structure.
|
||||
//
|
||||
Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA));
|
||||
if (Private == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE;
|
||||
Private->Controller = ControllerHandle;
|
||||
Private->Image = This->ImageHandle;
|
||||
Private->UsingIpv6 = FALSE;
|
||||
InitializeListHead (&Private->CacheList);
|
||||
|
||||
//
|
||||
// Create DHCP child instance.
|
||||
//
|
||||
Status = NetLibCreateServiceChild (
|
||||
ControllerHandle,
|
||||
This->DriverBindingHandle,
|
||||
&gEfiDhcp4ServiceBindingProtocolGuid,
|
||||
&Private->Dhcp4Child
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
Private->Dhcp4Child,
|
||||
&gEfiDhcp4ProtocolGuid,
|
||||
(VOID **) &Private->Dhcp4,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the Ip4Config2 protocol, it's required to configure the default gateway address.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiIp4Config2ProtocolGuid,
|
||||
(VOID **) &Private->Ip4Config2,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the NII interface if it exists, it's not required.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiNetworkInterfaceIdentifierProtocolGuid_31,
|
||||
(VOID **) &Private->Nii,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Private->Nii = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Open Device Path Protocol to prepare for appending IP and URI node.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
(VOID **) &Private->ParentDevicePath,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Append IPv4 device path node.
|
||||
//
|
||||
Node = AllocateZeroPool (sizeof (IPv4_DEVICE_PATH));
|
||||
if (Node == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_ERROR;
|
||||
}
|
||||
Node->Ipv4.Header.Type = MESSAGING_DEVICE_PATH;
|
||||
Node->Ipv4.Header.SubType = MSG_IPv4_DP;
|
||||
SetDevicePathNodeLength (Node, sizeof (IPv4_DEVICE_PATH));
|
||||
Node->Ipv4.StaticIpAddress = FALSE;
|
||||
DevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
|
||||
FreePool (Node);
|
||||
if (DevicePath == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Append URI device path node.
|
||||
//
|
||||
Node = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL));
|
||||
if (Node == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_ERROR;
|
||||
}
|
||||
Node->DevPath.Type = MESSAGING_DEVICE_PATH;
|
||||
Node->DevPath.SubType = MSG_URI_DP;
|
||||
SetDevicePathNodeLength (Node, sizeof (EFI_DEVICE_PATH_PROTOCOL));
|
||||
Private->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
|
||||
FreePool (Node);
|
||||
FreePool (DevicePath);
|
||||
if (Private->DevicePath == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a child handle for the HTTP boot and install DevPath and Load file protocol on it.
|
||||
//
|
||||
CopyMem (&Private->LoadFile, &gHttpBootDxeLoadFile, sizeof (Private->LoadFile));
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&Private->ChildHandle,
|
||||
&gEfiLoadFileProtocolGuid,
|
||||
&Private->LoadFile,
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
Private->DevicePath,
|
||||
NULL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between
|
||||
// NIC handle and the private data.
|
||||
//
|
||||
Status = gBS->InstallProtocolInterface (
|
||||
&ControllerHandle,
|
||||
&gEfiCallerIdGuid,
|
||||
EFI_NATIVE_INTERFACE,
|
||||
&Private->Id
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Open the Caller Id child to setup a parent-child relationship between
|
||||
// real NIC handle and the HTTP boot child handle.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiCallerIdGuid,
|
||||
(VOID **) &Id,
|
||||
This->DriverBindingHandle,
|
||||
Private->ChildHandle,
|
||||
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
ON_ERROR:
|
||||
|
||||
HttpBootDestroyIp4Children (This, Private);
|
||||
FreePool (Private);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Stops a device controller or a bus controller.
|
||||
|
||||
The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
|
||||
As a result, much of the error checking on the parameters to Stop() has been moved
|
||||
into this common boot service. It is legal to call Stop() from other locations,
|
||||
but the following calling restrictions must be followed, or the system behavior will not be deterministic.
|
||||
1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
|
||||
same driver's Start() function.
|
||||
2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
|
||||
EFI_HANDLE. In addition, all of these handles must have been created in this driver's
|
||||
Start() function, and the Start() function must have called OpenProtocol() on
|
||||
ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
|
||||
|
||||
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] ControllerHandle A handle to the device being stopped. The handle must
|
||||
support a bus specific I/O protocol for the driver
|
||||
to use to stop the device.
|
||||
@param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
|
||||
@param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
|
||||
if NumberOfChildren is 0.
|
||||
|
||||
@retval EFI_SUCCESS The device was stopped.
|
||||
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootIp4DxeDriverBindingStop (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN UINTN NumberOfChildren,
|
||||
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_LOAD_FILE_PROTOCOL *LoadFile;
|
||||
HTTP_BOOT_PRIVATE_DATA *Private;
|
||||
EFI_HANDLE NicHandle;
|
||||
UINT32 *Id;
|
||||
|
||||
//
|
||||
// Try to get the Load File Protocol from the controller handle.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiLoadFileProtocolGuid,
|
||||
(VOID **) &LoadFile,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// If failed, try to find the NIC handle for this controller.
|
||||
//
|
||||
NicHandle = HttpBootGetNicByIp4Children (ControllerHandle);
|
||||
if (NicHandle == NULL) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Try to retrieve the private data by the Caller Id Guid.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
NicHandle,
|
||||
&gEfiCallerIdGuid,
|
||||
(VOID **) &Id,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID (Id);
|
||||
} else {
|
||||
Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (LoadFile);
|
||||
NicHandle = Private->Controller;
|
||||
}
|
||||
|
||||
//
|
||||
// Disable the HTTP boot function.
|
||||
//
|
||||
Status = HttpBootStop (Private);
|
||||
if (Status != EFI_SUCCESS && Status != EFI_NOT_STARTED) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Destory all child instance and uninstall protocol interface.
|
||||
//
|
||||
HttpBootDestroyIp4Children (This, Private);
|
||||
|
||||
//
|
||||
// Release the cached data.
|
||||
//
|
||||
HttpBootFreeCacheList (Private);
|
||||
|
||||
gBS->UninstallProtocolInterface (
|
||||
NicHandle,
|
||||
&gEfiCallerIdGuid,
|
||||
&Private->Id
|
||||
);
|
||||
FreePool (Private);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
This is the declaration of an EFI image entry point. This entry point is
|
||||
the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
|
||||
both device drivers and bus drivers.
|
||||
|
||||
@param[in] ImageHandle The firmware allocated handle for the UEFI image.
|
||||
@param[in] SystemTable A pointer to the EFI System Table.
|
||||
|
||||
@retval EFI_SUCCESS The operation completed successfully.
|
||||
@retval Others An unexpected error occurred.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootDxeDriverEntryPoint (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
//
|
||||
// Install UEFI Driver Model protocol(s).
|
||||
//
|
||||
return EfiLibInstallDriverBindingComponentName2 (
|
||||
ImageHandle,
|
||||
SystemTable,
|
||||
&gHttpBootIp4DxeDriverBinding,
|
||||
ImageHandle,
|
||||
&gHttpBootDxeComponentName,
|
||||
&gHttpBootDxeComponentName2
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,303 @@
|
|||
/** @file
|
||||
UEFI HTTP boot driver's private data structure and interfaces declaration.
|
||||
|
||||
Copyright (c) 2015, 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 that 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.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __EFI_HTTP_BOOT_DXE_H__
|
||||
#define __EFI_HTTP_BOOT_DXE_H__
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
//
|
||||
// Libraries
|
||||
//
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/NetLib.h>
|
||||
#include <Library/HttpLib.h>
|
||||
|
||||
//
|
||||
// UEFI Driver Model Protocols
|
||||
//
|
||||
#include <Protocol/DriverBinding.h>
|
||||
#include <Protocol/ComponentName2.h>
|
||||
#include <Protocol/ComponentName.h>
|
||||
|
||||
//
|
||||
// Consumed Protocols
|
||||
//
|
||||
#include <Protocol/NetworkInterfaceIdentifier.h>
|
||||
#include <Protocol/Dhcp4.h>
|
||||
#include <Protocol/Http.h>
|
||||
#include <Protocol/Ip4Config2.h>
|
||||
|
||||
//
|
||||
// Produced Protocols
|
||||
//
|
||||
#include <Protocol/LoadFile.h>
|
||||
|
||||
//
|
||||
// Driver Version
|
||||
//
|
||||
#define HTTP_BOOT_DXE_VERSION 0xa
|
||||
|
||||
//
|
||||
// Protocol instances
|
||||
//
|
||||
extern EFI_DRIVER_BINDING_PROTOCOL gHttpBootDxeDriverBinding;
|
||||
extern EFI_COMPONENT_NAME2_PROTOCOL gHttpBootDxeComponentName2;
|
||||
extern EFI_COMPONENT_NAME_PROTOCOL gHttpBootDxeComponentName;
|
||||
|
||||
//
|
||||
// Private data structure
|
||||
//
|
||||
typedef struct _HTTP_BOOT_PRIVATE_DATA HTTP_BOOT_PRIVATE_DATA;
|
||||
|
||||
//
|
||||
// Include files with internal function prototypes
|
||||
//
|
||||
#include "HttpBootComponentName.h"
|
||||
#include "HttpBootDhcp4.h"
|
||||
#include "HttpBootImpl.h"
|
||||
#include "HttpBootSupport.h"
|
||||
#include "HttpBootClient.h"
|
||||
|
||||
typedef union {
|
||||
HTTP_BOOT_DHCP4_PACKET_CACHE Dhcp4;
|
||||
} HTTP_BOOT_DHCP_PACKET_CACHE;
|
||||
|
||||
struct _HTTP_BOOT_PRIVATE_DATA {
|
||||
UINT32 Signature;
|
||||
EFI_HANDLE Controller;
|
||||
EFI_HANDLE Image;
|
||||
|
||||
//
|
||||
// Cousumed children
|
||||
//
|
||||
EFI_HANDLE Dhcp4Child;
|
||||
HTTP_IO HttpIo;
|
||||
BOOLEAN HttpCreated;
|
||||
|
||||
//
|
||||
// Consumed protocol
|
||||
//
|
||||
EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;
|
||||
EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
|
||||
EFI_DHCP4_PROTOCOL *Dhcp4;
|
||||
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
|
||||
|
||||
//
|
||||
// Produced children
|
||||
//
|
||||
EFI_HANDLE ChildHandle;
|
||||
|
||||
//
|
||||
// Produced protocol
|
||||
//
|
||||
EFI_LOAD_FILE_PROTOCOL LoadFile;
|
||||
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
||||
UINT32 Id;
|
||||
|
||||
//
|
||||
// Mode data
|
||||
//
|
||||
BOOLEAN UsingIpv6;
|
||||
BOOLEAN Started;
|
||||
EFI_IP_ADDRESS StationIp;
|
||||
EFI_IP_ADDRESS SubnetMask;
|
||||
EFI_IP_ADDRESS GatewayIp;
|
||||
UINT16 Port;
|
||||
CHAR8 *BootFileUri;
|
||||
VOID *BootFileUriParser;
|
||||
UINTN BootFileSize;
|
||||
|
||||
//
|
||||
// Cached HTTP data
|
||||
//
|
||||
LIST_ENTRY CacheList;
|
||||
|
||||
//
|
||||
// Cached DHCP offer
|
||||
//
|
||||
// OfferIndex records the index of DhcpOffer[] buffer, and OfferCount records the num of each type of offer.
|
||||
//
|
||||
// It supposed that
|
||||
//
|
||||
// OfferNum: 8
|
||||
// OfferBuffer: [ProxyNameUri, DhcpNameUri, DhcpIpUri, ProxyNameUri, ProxyIpUri, DhcpOnly, DhcpIpUri, DhcpNameUriDns]
|
||||
// (OfferBuffer is 0-based.)
|
||||
//
|
||||
// And assume that (DhcpIpUri is the first priority actually.)
|
||||
//
|
||||
// SelectIndex: 5
|
||||
// SelectProxyType: HttpOfferTypeProxyIpUri
|
||||
// (SelectIndex is 1-based, and 0 means no one is selected.)
|
||||
//
|
||||
// So it should be
|
||||
//
|
||||
// DhcpIpUri DhcpNameUriDns DhcpDns DhcpOnly ProxyNameUri ProxyIpUri DhcpNameUri
|
||||
// OfferCount: [ 2, 1, 0, 1, 2, 1, 1]
|
||||
//
|
||||
// OfferIndex: {[ 2, 7, 0, 5, 0, *4, 1]
|
||||
// [ 6, 0, 0, 0, 3, 0, 0]
|
||||
// [ 0, 0, 0, 0, 0, 0, 0]
|
||||
// ... ]}
|
||||
// (OfferIndex is 0-based.)
|
||||
//
|
||||
//
|
||||
UINT32 SelectIndex;
|
||||
UINT32 SelectProxyType;
|
||||
HTTP_BOOT_DHCP_PACKET_CACHE OfferBuffer[HTTP_BOOT_OFFER_MAX_NUM];
|
||||
UINT32 OfferNum;
|
||||
UINT32 OfferCount[HttpOfferTypeMax];
|
||||
UINT32 OfferIndex[HttpOfferTypeMax][HTTP_BOOT_OFFER_MAX_NUM];
|
||||
};
|
||||
|
||||
#define HTTP_BOOT_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('H', 'B', 'P', 'D')
|
||||
#define HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE(a) CR (a, HTTP_BOOT_PRIVATE_DATA, LoadFile, HTTP_BOOT_PRIVATE_DATA_SIGNATURE)
|
||||
#define HTTP_BOOT_PRIVATE_DATA_FROM_ID(a) CR (a, HTTP_BOOT_PRIVATE_DATA, Id, HTTP_BOOT_PRIVATE_DATA_SIGNATURE)
|
||||
|
||||
extern EFI_LOAD_FILE_PROTOCOL gHttpBootDxeLoadFile;
|
||||
|
||||
/**
|
||||
Tests to see if this driver supports a given controller. If a child device is provided,
|
||||
it further tests to see if this driver supports creating a handle for the specified child device.
|
||||
|
||||
This function checks to see if the driver specified by This supports the device specified by
|
||||
ControllerHandle. Drivers will typically use the device path attached to
|
||||
ControllerHandle and/or the services from the bus I/O abstraction attached to
|
||||
ControllerHandle to determine if the driver supports ControllerHandle. This function
|
||||
may be called many times during platform initialization. In order to reduce boot times, the tests
|
||||
performed by this function must be very small, and take as little time as possible to execute. This
|
||||
function must not change the state of any hardware devices, and this function must be aware that the
|
||||
device specified by ControllerHandle may already be managed by the same driver or a
|
||||
different driver. This function must match its calls to AllocatePages() with FreePages(),
|
||||
AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
|
||||
Because ControllerHandle may have been previously started by the same driver, if a protocol is
|
||||
already in the opened state, then it must not be closed with CloseProtocol(). This is required
|
||||
to guarantee the state of ControllerHandle is not modified by this function.
|
||||
|
||||
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] ControllerHandle The handle of the controller to test. This handle
|
||||
must support a protocol interface that supplies
|
||||
an I/O abstraction to the driver.
|
||||
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
|
||||
parameter is ignored by device drivers, and is optional for bus
|
||||
drivers. For bus drivers, if this parameter is not NULL, then
|
||||
the bus driver must determine if the bus controller specified
|
||||
by ControllerHandle and the child controller specified
|
||||
by RemainingDevicePath are both supported by this
|
||||
bus driver.
|
||||
|
||||
@retval EFI_SUCCESS The device specified by ControllerHandle and
|
||||
RemainingDevicePath is supported by the driver specified by This.
|
||||
@retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is already being managed by the driver
|
||||
specified by This.
|
||||
@retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is already being managed by a different
|
||||
driver or an application that requires exclusive access.
|
||||
Currently not implemented.
|
||||
@retval EFI_UNSUPPORTED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is not supported by the driver specified by This.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootIp4DxeDriverBindingSupported (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
Starts a device controller or a bus controller.
|
||||
|
||||
The Start() function is designed to be invoked from the EFI boot service ConnectController().
|
||||
As a result, much of the error checking on the parameters to Start() has been moved into this
|
||||
common boot service. It is legal to call Start() from other locations,
|
||||
but the following calling restrictions must be followed, or the system behavior will not be deterministic.
|
||||
1. ControllerHandle must be a valid EFI_HANDLE.
|
||||
2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
|
||||
EFI_DEVICE_PATH_PROTOCOL.
|
||||
3. Prior to calling Start(), the Supported() function for the driver specified by This must
|
||||
have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
|
||||
|
||||
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] ControllerHandle The handle of the controller to start. This handle
|
||||
must support a protocol interface that supplies
|
||||
an I/O abstraction to the driver.
|
||||
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
|
||||
parameter is ignored by device drivers, and is optional for bus
|
||||
drivers. For a bus driver, if this parameter is NULL, then handles
|
||||
for all the children of Controller are created by this driver.
|
||||
If this parameter is not NULL and the first Device Path Node is
|
||||
not the End of Device Path Node, then only the handle for the
|
||||
child device specified by the first Device Path Node of
|
||||
RemainingDevicePath is created by this driver.
|
||||
If the first Device Path Node of RemainingDevicePath is
|
||||
the End of Device Path Node, no child handle is created by this
|
||||
driver.
|
||||
|
||||
@retval EFI_SUCCESS The device was started.
|
||||
@retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
|
||||
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
|
||||
@retval Others The driver failded to start the device.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootIp4DxeDriverBindingStart (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
Stops a device controller or a bus controller.
|
||||
|
||||
The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
|
||||
As a result, much of the error checking on the parameters to Stop() has been moved
|
||||
into this common boot service. It is legal to call Stop() from other locations,
|
||||
but the following calling restrictions must be followed, or the system behavior will not be deterministic.
|
||||
1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
|
||||
same driver's Start() function.
|
||||
2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
|
||||
EFI_HANDLE. In addition, all of these handles must have been created in this driver's
|
||||
Start() function, and the Start() function must have called OpenProtocol() on
|
||||
ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
|
||||
|
||||
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] ControllerHandle A handle to the device being stopped. The handle must
|
||||
support a bus specific I/O protocol for the driver
|
||||
to use to stop the device.
|
||||
@param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
|
||||
@param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
|
||||
if NumberOfChildren is 0.
|
||||
|
||||
@retval EFI_SUCCESS The device was stopped.
|
||||
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootIp4DxeDriverBindingStop (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN UINTN NumberOfChildren,
|
||||
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
|
||||
);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,68 @@
|
|||
## @file
|
||||
# This modules produce the Load File Protocol for UEFI HTTP boot.
|
||||
#
|
||||
# Copyright (c) 2015, 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.
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = HttpBootDxe
|
||||
FILE_GUID = ecebcb00-d9c8-11e4-af3d-8cdcd426c973
|
||||
MODULE_TYPE = UEFI_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = HttpBootDxeDriverEntryPoint
|
||||
UNLOAD_IMAGE = NetLibDefaultUnload
|
||||
MODULE_UNI_FILE = HttpBootDxe.uni
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[Sources]
|
||||
HttpBootDxe.h
|
||||
HttpBootDxe.c
|
||||
HttpBootComponentName.h
|
||||
HttpBootComponentName.c
|
||||
HttpBootImpl.h
|
||||
HttpBootImpl.c
|
||||
HttpBootDhcp4.h
|
||||
HttpBootDhcp4.c
|
||||
HttpBootSupport.h
|
||||
HttpBootSupport.c
|
||||
HttpBootClient.h
|
||||
HttpBootClient.c
|
||||
|
||||
[LibraryClasses]
|
||||
UefiDriverEntryPoint
|
||||
UefiBootServicesTableLib
|
||||
MemoryAllocationLib
|
||||
BaseLib
|
||||
UefiLib
|
||||
DevicePathLib
|
||||
DebugLib
|
||||
NetLib
|
||||
HttpLib
|
||||
|
||||
[Protocols]
|
||||
## TO_START
|
||||
## BY_START
|
||||
gEfiDevicePathProtocolGuid
|
||||
|
||||
gEfiLoadFileProtocolGuid ## BY_START
|
||||
gEfiHttpServiceBindingProtocolGuid ## CONSUMES
|
||||
gEfiHttpProtocolGuid ## CONSUMES
|
||||
gEfiDhcp4ServiceBindingProtocolGuid ## TO_START
|
||||
gEfiDhcp4ProtocolGuid ## TO_START
|
||||
gEfiIp4Config2ProtocolGuid ## TO_START
|
||||
gEfiNetworkInterfaceIdentifierProtocolGuid_31 ## SOMETIMES_CONSUMES
|
||||
|
||||
[UserExtensions.TianoCore."ExtraFiles"]
|
||||
HttpBootDxeExtra.uni
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,352 @@
|
|||
/** @file
|
||||
The implementation of EFI_LOAD_FILE_PROTOCOL for UEFI HTTP boot.
|
||||
|
||||
Copyright (c) 2015, 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 that 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 "HttpBootDxe.h"
|
||||
|
||||
/**
|
||||
Enable the use of UEFI HTTP boot function.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
|
||||
@retval EFI_SUCCESS HTTP boot was successfully enabled.
|
||||
@retval EFI_INVALID_PARAMETER Private is NULL.
|
||||
@retval EFI_ALREADY_STARTED The driver is already in started state.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootStart (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
if (Private == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (Private->Started) {
|
||||
return EFI_ALREADY_STARTED;
|
||||
}
|
||||
|
||||
if (!Private->UsingIpv6) {
|
||||
//
|
||||
// Init the content of cached DHCP offer list.
|
||||
//
|
||||
ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer));
|
||||
for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {
|
||||
Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = HTTP_BOOT_DHCP4_PACKET_MAX_SIZE;
|
||||
}
|
||||
} else {
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
|
||||
Private->Started = TRUE;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Attempt to complete a DHCPv4 D.O.R.A sequence to retrieve the boot resource information.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
|
||||
@retval EFI_SUCCESS Boot info was successfully retrieved.
|
||||
@retval EFI_INVALID_PARAMETER Private is NULL.
|
||||
@retval EFI_NOT_STARTED The driver is in stopped state.
|
||||
@retval EFI_DEVICE_ERROR An unexpected network error occurred.
|
||||
@retval Others Other errors as indicated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootDhcp (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
if (Private == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!Private->Started) {
|
||||
return EFI_NOT_STARTED;
|
||||
}
|
||||
|
||||
Status = EFI_DEVICE_ERROR;
|
||||
|
||||
if (!Private->UsingIpv6) {
|
||||
Status = HttpBootDhcp4Dora (Private);
|
||||
} else {
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Attempt to download the boot file through HTTP message exchange.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
@param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
|
||||
code of EFI_SUCCESS, the amount of data transferred to
|
||||
Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
|
||||
the size of Buffer required to retrieve the requested file.
|
||||
@param[in] Buffer The memory buffer to transfer the file to. If Buffer is NULL,
|
||||
then the size of the requested file is returned in
|
||||
BufferSize.
|
||||
|
||||
@retval EFI_SUCCESS Boot file was loaded successfully.
|
||||
@retval EFI_INVALID_PARAMETER Private is NULL.
|
||||
@retval EFI_NOT_STARTED The driver is in stopped state.
|
||||
@retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the boot file. BufferSize has
|
||||
been updated with the size needed to complete the request.
|
||||
@retval EFI_DEVICE_ERROR An unexpected network error occurred.
|
||||
@retval Others Other errors as indicated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootLoadFile (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private,
|
||||
IN OUT UINTN *BufferSize,
|
||||
IN VOID *Buffer OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
if (Private == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!Private->Started) {
|
||||
return EFI_NOT_STARTED;
|
||||
}
|
||||
|
||||
Status = EFI_DEVICE_ERROR;
|
||||
|
||||
if (Private->BootFileUri == NULL) {
|
||||
//
|
||||
// Parse the cached offer to get the boot file URL first.
|
||||
//
|
||||
Status = HttpBootDiscoverBootInfo (Private);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Private->HttpCreated) {
|
||||
//
|
||||
// Create HTTP child.
|
||||
//
|
||||
Status = HttpBootCreateHttpIo (Private);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
if (Private->BootFileSize == 0) {
|
||||
//
|
||||
// Discover the information about the bootfile if we haven't.
|
||||
//
|
||||
|
||||
//
|
||||
// Try to use HTTP HEAD method.
|
||||
//
|
||||
Status = HttpBootGetBootFile (
|
||||
Private,
|
||||
TRUE,
|
||||
&Private->BootFileSize,
|
||||
NULL
|
||||
);
|
||||
if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
|
||||
//
|
||||
// Failed to get file size by HEAD method, may be trunked encoding, try HTTP GET method.
|
||||
//
|
||||
ASSERT (Private->BootFileSize == 0);
|
||||
Status = HttpBootGetBootFile (
|
||||
Private,
|
||||
FALSE,
|
||||
&Private->BootFileSize,
|
||||
NULL
|
||||
);
|
||||
if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*BufferSize < Private->BootFileSize) {
|
||||
*BufferSize = Private->BootFileSize;
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
//
|
||||
// Load the boot file into Buffer
|
||||
//
|
||||
return HttpBootGetBootFile (
|
||||
Private,
|
||||
FALSE,
|
||||
BufferSize,
|
||||
Buffer
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Disable the use of UEFI HTTP boot function.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
|
||||
@retval EFI_SUCCESS HTTP boot was successfully disabled.
|
||||
@retval EFI_NOT_STARTED The driver is already in stopped state.
|
||||
@retval EFI_INVALID_PARAMETER Private is NULL.
|
||||
@retval Others Unexpected error when stop the function.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootStop (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
if (Private == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!Private->Started) {
|
||||
return EFI_NOT_STARTED;
|
||||
}
|
||||
|
||||
if (Private->HttpCreated) {
|
||||
HttpIoDestroyIo (&Private->HttpIo);
|
||||
Private->HttpCreated = FALSE;
|
||||
}
|
||||
|
||||
Private->Started = FALSE;
|
||||
ZeroMem (&Private->StationIp, sizeof (EFI_IP_ADDRESS));
|
||||
ZeroMem (&Private->SubnetMask, sizeof (EFI_IP_ADDRESS));
|
||||
ZeroMem (&Private->GatewayIp, sizeof (EFI_IP_ADDRESS));
|
||||
Private->Port = 0;
|
||||
Private->BootFileUri = NULL;
|
||||
Private->BootFileUriParser = NULL;
|
||||
Private->BootFileSize = 0;
|
||||
Private->SelectIndex = 0;
|
||||
Private->SelectProxyType = HttpOfferTypeMax;
|
||||
|
||||
if (!Private->UsingIpv6) {
|
||||
for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {
|
||||
if (Private->OfferBuffer[Index].Dhcp4.UriParser) {
|
||||
HttpUrlFreeParser (Private->OfferBuffer[Index].Dhcp4.UriParser);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
|
||||
ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer));
|
||||
Private->OfferNum = 0;
|
||||
ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
|
||||
ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Causes the driver to load a specified file.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
@param FilePath The device specific path of the file to load.
|
||||
@param BootPolicy If TRUE, indicates that the request originates from the
|
||||
boot manager is attempting to load FilePath as a boot
|
||||
selection. If FALSE, then FilePath must match as exact file
|
||||
to be loaded.
|
||||
@param BufferSize On input the size of Buffer in bytes. On output with a return
|
||||
code of EFI_SUCCESS, the amount of data transferred to
|
||||
Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
|
||||
the size of Buffer required to retrieve the requested file.
|
||||
@param Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
|
||||
then the size of the requested file is returned in
|
||||
BufferSize.
|
||||
|
||||
@retval EFI_SUCCESS The file was loaded.
|
||||
@retval EFI_UNSUPPORTED The device does not support the provided BootPolicy
|
||||
@retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
|
||||
BufferSize is NULL.
|
||||
@retval EFI_NO_MEDIA No medium was present to load the file.
|
||||
@retval EFI_DEVICE_ERROR The file was not loaded due to a device error.
|
||||
@retval EFI_NO_RESPONSE The remote system did not respond.
|
||||
@retval EFI_NOT_FOUND The file was not found.
|
||||
@retval EFI_ABORTED The file load process was manually cancelled.
|
||||
@retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
|
||||
BufferSize has been updated with the size needed to complete
|
||||
the request.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
HttpBootDxeLoadFile (
|
||||
IN EFI_LOAD_FILE_PROTOCOL *This,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
|
||||
IN BOOLEAN BootPolicy,
|
||||
IN OUT UINTN *BufferSize,
|
||||
IN VOID *Buffer OPTIONAL
|
||||
)
|
||||
{
|
||||
HTTP_BOOT_PRIVATE_DATA *Private;
|
||||
BOOLEAN MediaPresent;
|
||||
EFI_STATUS Status;
|
||||
|
||||
if (This == NULL || BufferSize == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Only support BootPolicy
|
||||
//
|
||||
if (!BootPolicy) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (This);
|
||||
|
||||
//
|
||||
// Check media status before HTTP boot start
|
||||
//
|
||||
MediaPresent = TRUE;
|
||||
NetLibDetectMedia (Private->Controller, &MediaPresent);
|
||||
if (!MediaPresent) {
|
||||
return EFI_NO_MEDIA;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize HTTP boot and load the boot file.
|
||||
//
|
||||
Status = HttpBootStart (Private);
|
||||
if (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED) {
|
||||
Status = HttpBootLoadFile (Private, BufferSize, Buffer);
|
||||
}
|
||||
|
||||
if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) {
|
||||
HttpBootStop (Private);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
///
|
||||
/// Load File Protocol instance
|
||||
///
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED
|
||||
EFI_LOAD_FILE_PROTOCOL gHttpBootDxeLoadFile = {
|
||||
HttpBootDxeLoadFile
|
||||
};
|
|
@ -0,0 +1,50 @@
|
|||
/** @file
|
||||
The declaration of UEFI HTTP boot function.
|
||||
|
||||
Copyright (c) 2015, 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 that 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.
|
||||
|
||||
**/
|
||||
#ifndef __EFI_HTTP_BOOT_IMPL_H__
|
||||
#define __EFI_HTTP_BOOT_IMPL_H__
|
||||
|
||||
/**
|
||||
Attempt to complete a DHCPv4 D.O.R.A sequence to retrieve the boot resource information.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
|
||||
@retval EFI_SUCCESS Boot info was successfully retrieved.
|
||||
@retval EFI_INVALID_PARAMETER Private is NULL.
|
||||
@retval EFI_NOT_STARTED The driver is in stopped state.
|
||||
@retval EFI_DEVICE_ERROR An unexpected network error occurred.
|
||||
@retval Others Other errors as indicated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootDhcp (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
);
|
||||
|
||||
/**
|
||||
Disable the use of UEFI HTTP boot function.
|
||||
|
||||
@param[in] Private The pointer to the driver's private data.
|
||||
|
||||
@retval EFI_SUCCESS HTTP boot was successfully disabled.
|
||||
@retval EFI_NOT_STARTED The driver is already in stopped state.
|
||||
@retval EFI_INVALID_PARAMETER Private is NULL.
|
||||
@retval Others Unexpected error when stop the function.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootStop (
|
||||
IN HTTP_BOOT_PRIVATE_DATA *Private
|
||||
);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,590 @@
|
|||
/** @file
|
||||
Support functions implementation for UEFI HTTP boot driver.
|
||||
|
||||
Copyright (c) 2015, 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 that 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 "HttpBootDxe.h"
|
||||
|
||||
|
||||
/**
|
||||
Get the Nic handle using any child handle in the IPv4 stack.
|
||||
|
||||
@param[in] ControllerHandle Pointer to child handle over IPv4.
|
||||
|
||||
@return NicHandle The pointer to the Nic handle.
|
||||
@return NULL Can't find the Nic handle.
|
||||
|
||||
**/
|
||||
EFI_HANDLE
|
||||
HttpBootGetNicByIp4Children (
|
||||
IN EFI_HANDLE ControllerHandle
|
||||
)
|
||||
{
|
||||
EFI_HANDLE NicHandle;
|
||||
|
||||
NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);
|
||||
if (NicHandle == NULL) {
|
||||
NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);
|
||||
if (NicHandle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NicHandle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This function is to convert UINTN to ASCII string with the required formatting.
|
||||
|
||||
@param[in] Number Numeric value to be converted.
|
||||
@param[in] Buffer The pointer to the buffer for ASCII string.
|
||||
@param[in] Length The length of the required format.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootUintnToAscDecWithFormat (
|
||||
IN UINTN Number,
|
||||
IN UINT8 *Buffer,
|
||||
IN INTN Length
|
||||
)
|
||||
{
|
||||
UINTN Remainder;
|
||||
|
||||
while (Length > 0) {
|
||||
Length--;
|
||||
Remainder = Number % 10;
|
||||
Number /= 10;
|
||||
Buffer[Length] = (UINT8) ('0' + Remainder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
This function is to display the IPv4 address.
|
||||
|
||||
@param[in] Ip The pointer to the IPv4 address.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootShowIp4Addr (
|
||||
IN EFI_IPv4_ADDRESS *Ip
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
for (Index = 0; Index < 4; Index++) {
|
||||
AsciiPrint ("%d", Ip->Addr[Index]);
|
||||
if (Index < 3) {
|
||||
AsciiPrint (".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Create a HTTP_IO_HEADER to hold the HTTP header items.
|
||||
|
||||
@param[in] MaxHeaderCount The maximun number of HTTP header in this holder.
|
||||
|
||||
@return A pointer of the HTTP header holder or NULL if failed.
|
||||
|
||||
**/
|
||||
HTTP_IO_HEADER *
|
||||
HttpBootCreateHeader (
|
||||
UINTN MaxHeaderCount
|
||||
)
|
||||
{
|
||||
HTTP_IO_HEADER *HttpIoHeader;
|
||||
|
||||
if (MaxHeaderCount == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HttpIoHeader = AllocateZeroPool (sizeof (HTTP_IO_HEADER) + MaxHeaderCount * sizeof (EFI_HTTP_HEADER));
|
||||
if (HttpIoHeader == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HttpIoHeader->MaxHeaderCount = MaxHeaderCount;
|
||||
HttpIoHeader->Headers = (EFI_HTTP_HEADER *) (HttpIoHeader + 1);
|
||||
|
||||
return HttpIoHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
Destroy the HTTP_IO_HEADER and release the resouces.
|
||||
|
||||
@param[in] HttpIoHeader Point to the HTTP header holder to be destroyed.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootFreeHeader (
|
||||
IN HTTP_IO_HEADER *HttpIoHeader
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
if (HttpIoHeader != NULL) {
|
||||
if (HttpIoHeader->HeaderCount != 0) {
|
||||
for (Index = 0; Index < HttpIoHeader->HeaderCount; Index++) {
|
||||
FreePool (HttpIoHeader->Headers[Index].FieldName);
|
||||
FreePool (HttpIoHeader->Headers[Index].FieldValue);
|
||||
}
|
||||
}
|
||||
FreePool (HttpIoHeader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Find a specified header field according to the field name.
|
||||
|
||||
@param[in] HeaderCount Number of HTTP header structures in Headers list.
|
||||
@param[in] Headers Array containing list of HTTP headers.
|
||||
@param[in] FieldName Null terminated string which describes a field name.
|
||||
|
||||
@return Pointer to the found header or NULL.
|
||||
|
||||
**/
|
||||
EFI_HTTP_HEADER *
|
||||
HttpBootFindHeader (
|
||||
IN UINTN HeaderCount,
|
||||
IN EFI_HTTP_HEADER *Headers,
|
||||
IN CHAR8 *FieldName
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
if (HeaderCount == 0 || Headers == NULL || FieldName == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (Index = 0; Index < HeaderCount; Index++){
|
||||
//
|
||||
// Field names are case-insensitive (RFC 2616).
|
||||
//
|
||||
if (AsciiStriCmp (Headers[Index].FieldName, FieldName) == 0) {
|
||||
return &Headers[Index];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
Set or update a HTTP header with the field name and corresponding value.
|
||||
|
||||
@param[in] HttpIoHeader Point to the HTTP header holder.
|
||||
@param[in] FieldName Null terminated string which describes a field name.
|
||||
@param[in] FieldValue Null terminated string which describes the corresponding field value.
|
||||
|
||||
@retval EFI_SUCCESS The HTTP header has been set or updated.
|
||||
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
|
||||
@retval EFI_OUT_OF_RESOURCES Insufficient resource to complete the operation.
|
||||
@retval Other Unexpected error happened.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootSetHeader (
|
||||
IN HTTP_IO_HEADER *HttpIoHeader,
|
||||
IN CHAR8 *FieldName,
|
||||
IN CHAR8 *FieldValue
|
||||
)
|
||||
{
|
||||
EFI_HTTP_HEADER *Header;
|
||||
UINTN StrSize;
|
||||
CHAR8 *NewFieldValue;
|
||||
|
||||
if (HttpIoHeader == NULL || FieldName == NULL || FieldValue == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Header = HttpBootFindHeader (HttpIoHeader->HeaderCount, HttpIoHeader->Headers, FieldName);
|
||||
if (Header == NULL) {
|
||||
//
|
||||
// Add a new header.
|
||||
//
|
||||
if (HttpIoHeader->HeaderCount >= HttpIoHeader->MaxHeaderCount) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
Header = &HttpIoHeader->Headers[HttpIoHeader->HeaderCount];
|
||||
|
||||
StrSize = AsciiStrSize (FieldName);
|
||||
Header->FieldName = AllocatePool (StrSize);
|
||||
if (Header->FieldName == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
CopyMem (Header->FieldName, FieldName, StrSize);
|
||||
Header->FieldName[StrSize -1] = '\0';
|
||||
|
||||
StrSize = AsciiStrSize (FieldValue);
|
||||
Header->FieldValue = AllocatePool (StrSize);
|
||||
if (Header->FieldValue == NULL) {
|
||||
FreePool (Header->FieldName);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
CopyMem (Header->FieldValue, FieldValue, StrSize);
|
||||
Header->FieldValue[StrSize -1] = '\0';
|
||||
|
||||
HttpIoHeader->HeaderCount++;
|
||||
} else {
|
||||
//
|
||||
// Update an existing one.
|
||||
//
|
||||
StrSize = AsciiStrSize (FieldValue);
|
||||
NewFieldValue = AllocatePool (StrSize);
|
||||
if (NewFieldValue == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
CopyMem (NewFieldValue, FieldValue, StrSize);
|
||||
NewFieldValue[StrSize -1] = '\0';
|
||||
|
||||
if (Header->FieldValue != NULL) {
|
||||
FreePool (Header->FieldValue);
|
||||
}
|
||||
Header->FieldValue = NewFieldValue;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Notify the callback function when an event is triggered.
|
||||
|
||||
@param[in] Event The triggered event.
|
||||
@param[in] Context The opaque parameter to the function.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
HttpIoCommonNotify (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
*((BOOLEAN *) Context) = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Create a HTTP_IO to access the HTTP service. It will create and configure
|
||||
a HTTP child handle.
|
||||
|
||||
@param[in] Image The handle of the driver image.
|
||||
@param[in] Controller The handle of the controller.
|
||||
@param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
|
||||
@param[in] ConfigData The HTTP_IO configuration data.
|
||||
@param[out] HttpIo The HTTP_IO.
|
||||
|
||||
@retval EFI_SUCCESS The HTTP_IO is created and configured.
|
||||
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
||||
@retval EFI_UNSUPPORTED One or more of the control options are not
|
||||
supported in the implementation.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
@retval Others Failed to create the HTTP_IO or configure it.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpIoCreateIo (
|
||||
IN EFI_HANDLE Image,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN UINT8 IpVersion,
|
||||
IN HTTP_IO_CONFIG_DATA *ConfigData,
|
||||
OUT HTTP_IO *HttpIo
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_HTTP_CONFIG_DATA HttpConfigData;
|
||||
EFI_HTTPv4_ACCESS_POINT Http4AccessPoint;
|
||||
EFI_HTTP_PROTOCOL *Http;
|
||||
EFI_EVENT Event;
|
||||
|
||||
if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (HttpIo == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (IpVersion != IP_VERSION_4 && IpVersion != IP_VERSION_6) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
ZeroMem (HttpIo, sizeof (HTTP_IO));
|
||||
|
||||
//
|
||||
// Create the HTTP child instance and get the HTTP protocol.
|
||||
//
|
||||
Status = NetLibCreateServiceChild (
|
||||
Controller,
|
||||
Image,
|
||||
&gEfiHttpServiceBindingProtocolGuid,
|
||||
&HttpIo->Handle
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
HttpIo->Handle,
|
||||
&gEfiHttpProtocolGuid,
|
||||
(VOID **) &Http,
|
||||
Image,
|
||||
Controller,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
if (EFI_ERROR (Status) || (Http == NULL)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Init the configuration data and configure the HTTP child.
|
||||
//
|
||||
HttpIo->Image = Image;
|
||||
HttpIo->Controller = Controller;
|
||||
HttpIo->IpVersion = IpVersion;
|
||||
HttpIo->Http = Http;
|
||||
|
||||
ZeroMem (&HttpConfigData, sizeof (EFI_HTTP_CONFIG_DATA));
|
||||
HttpConfigData.HttpVersion = HttpVersion11;
|
||||
HttpConfigData.TimeOutMillisec = ConfigData->Config4.RequestTimeOut;
|
||||
if (HttpIo->IpVersion == IP_VERSION_4) {
|
||||
HttpConfigData.LocalAddressIsIPv6 = FALSE;
|
||||
|
||||
Http4AccessPoint.UseDefaultAddress = ConfigData->Config4.UseDefaultAddress;
|
||||
Http4AccessPoint.LocalPort = ConfigData->Config4.LocalPort;
|
||||
IP4_COPY_ADDRESS (&Http4AccessPoint.LocalAddress, &ConfigData->Config4.LocalIp);
|
||||
IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet, &ConfigData->Config4.SubnetMask);
|
||||
HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint;
|
||||
} else {
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
|
||||
Status = Http->Configure (Http, &HttpConfigData);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Create events for variuos asynchronous operations.
|
||||
//
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_NOTIFY,
|
||||
HttpIoCommonNotify,
|
||||
&HttpIo->IsTxDone,
|
||||
&Event
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
HttpIo->ReqToken.Event = Event;
|
||||
HttpIo->ReqToken.Message = &HttpIo->ReqMessage;
|
||||
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_NOTIFY,
|
||||
HttpIoCommonNotify,
|
||||
&HttpIo->IsRxDone,
|
||||
&Event
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
HttpIo->RspToken.Event = Event;
|
||||
HttpIo->RspToken.Message = &HttpIo->RspMessage;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
ON_ERROR:
|
||||
HttpIoDestroyIo (HttpIo);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Destroy the HTTP_IO and release the resouces.
|
||||
|
||||
@param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpIoDestroyIo (
|
||||
IN HTTP_IO *HttpIo
|
||||
)
|
||||
{
|
||||
EFI_HTTP_PROTOCOL *Http;
|
||||
EFI_EVENT Event;
|
||||
|
||||
if (HttpIo == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Event = HttpIo->ReqToken.Event;
|
||||
if (Event != NULL) {
|
||||
gBS->CloseEvent (Event);
|
||||
}
|
||||
|
||||
Event = HttpIo->RspToken.Event;
|
||||
if (Event != NULL) {
|
||||
gBS->CloseEvent (Event);
|
||||
}
|
||||
|
||||
Http = HttpIo->Http;
|
||||
if (Http != NULL) {
|
||||
Http->Configure (Http, NULL);
|
||||
gBS->CloseProtocol (
|
||||
HttpIo->Handle,
|
||||
&gEfiHttpProtocolGuid,
|
||||
HttpIo->Image,
|
||||
HttpIo->Controller
|
||||
);
|
||||
}
|
||||
|
||||
NetLibDestroyServiceChild (
|
||||
HttpIo->Controller,
|
||||
HttpIo->Image,
|
||||
&gEfiHttpServiceBindingProtocolGuid,
|
||||
HttpIo->Handle
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Synchronously send a HTTP REQUEST message to the server.
|
||||
|
||||
@param[in] HttpIo The HttpIo wrapping the HTTP service.
|
||||
@param[in] Request A pointer to storage such data as URL and HTTP method.
|
||||
@param[in] HeaderCount Number of HTTP header structures in Headers list.
|
||||
@param[in] Headers Array containing list of HTTP headers.
|
||||
@param[in] BodyLength Length in bytes of the HTTP body.
|
||||
@param[in] Body Body associated with the HTTP request.
|
||||
|
||||
@retval EFI_SUCCESS The HTTP request is trasmitted.
|
||||
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
@retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
|
||||
@retval Others Other errors as indicated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpIoSendRequest (
|
||||
IN HTTP_IO *HttpIo,
|
||||
IN EFI_HTTP_REQUEST_DATA *Request,
|
||||
IN UINTN HeaderCount,
|
||||
IN EFI_HTTP_HEADER *Headers,
|
||||
IN UINTN BodyLength,
|
||||
IN VOID *Body
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_HTTP_PROTOCOL *Http;
|
||||
|
||||
if (HttpIo == NULL || HttpIo->Http == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
HttpIo->ReqToken.Status = EFI_NOT_READY;
|
||||
HttpIo->ReqToken.Message->Data.Request = Request;
|
||||
HttpIo->ReqToken.Message->HeaderCount = HeaderCount;
|
||||
HttpIo->ReqToken.Message->Headers = Headers;
|
||||
HttpIo->ReqToken.Message->BodyLength = BodyLength;
|
||||
HttpIo->ReqToken.Message->Body = Body;
|
||||
|
||||
//
|
||||
// Queue the request token to HTTP instances.
|
||||
//
|
||||
Http = HttpIo->Http;
|
||||
HttpIo->IsTxDone = FALSE;
|
||||
Status = Http->Request (
|
||||
Http,
|
||||
&HttpIo->ReqToken
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Poll the network until transmit finish.
|
||||
//
|
||||
while (!HttpIo->IsTxDone) {
|
||||
Http->Poll (Http);
|
||||
}
|
||||
|
||||
return HttpIo->ReqToken.Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Synchronously receive a HTTP RESPONSE message from the server.
|
||||
|
||||
@param[in] HttpIo The HttpIo wrapping the HTTP service.
|
||||
@param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header).
|
||||
FALSE to continue receive the previous response message.
|
||||
@param[out] ResponseData Point to a wrapper of the received response data.
|
||||
|
||||
@retval EFI_SUCCESS The HTTP resopnse is received.
|
||||
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
@retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
|
||||
@retval Others Other errors as indicated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpIoRecvResponse (
|
||||
IN HTTP_IO *HttpIo,
|
||||
IN BOOLEAN RecvMsgHeader,
|
||||
OUT HTTP_IO_RESOPNSE_DATA *ResponseData
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_HTTP_PROTOCOL *Http;
|
||||
|
||||
if (HttpIo == NULL || HttpIo->Http == NULL || ResponseData == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Queue the response token to HTTP instances.
|
||||
//
|
||||
HttpIo->RspToken.Status = EFI_NOT_READY;
|
||||
if (RecvMsgHeader) {
|
||||
HttpIo->RspToken.Message->Data.Response = &ResponseData->Response;
|
||||
} else {
|
||||
HttpIo->RspToken.Message->Data.Response = NULL;
|
||||
}
|
||||
HttpIo->RspToken.Message->HeaderCount = 0;
|
||||
HttpIo->RspToken.Message->Headers = NULL;
|
||||
HttpIo->RspToken.Message->BodyLength = ResponseData->BodyLength;
|
||||
HttpIo->RspToken.Message->Body = ResponseData->Body;
|
||||
|
||||
Http = HttpIo->Http;
|
||||
HttpIo->IsRxDone = FALSE;
|
||||
Status = Http->Response (
|
||||
Http,
|
||||
&HttpIo->RspToken
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Poll the network until transmit finish.
|
||||
//
|
||||
while (!HttpIo->IsRxDone) {
|
||||
Http->Poll (Http);
|
||||
}
|
||||
|
||||
//
|
||||
// Store the received data into the wrapper.
|
||||
//
|
||||
Status = HttpIo->ReqToken.Status;
|
||||
if (!EFI_ERROR (Status)) {
|
||||
ResponseData->HeaderCount = HttpIo->RspToken.Message->HeaderCount;
|
||||
ResponseData->Headers = HttpIo->RspToken.Message->Headers;
|
||||
ResponseData->BodyLength = HttpIo->RspToken.Message->BodyLength;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
/** @file
|
||||
Support functions declaration for UEFI HTTP boot driver.
|
||||
|
||||
Copyright (c) 2015, 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 that 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.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __EFI_HTTP_BOOT_SUPPORT_H__
|
||||
#define __EFI_HTTP_BOOT_SUPPORT_H__
|
||||
|
||||
/**
|
||||
Get the Nic handle using any child handle in the IPv4 stack.
|
||||
|
||||
@param[in] ControllerHandle Pointer to child handle over IPv4.
|
||||
|
||||
@return NicHandle The pointer to the Nic handle.
|
||||
@return NULL Can't find the Nic handle.
|
||||
|
||||
**/
|
||||
EFI_HANDLE
|
||||
HttpBootGetNicByIp4Children (
|
||||
IN EFI_HANDLE ControllerHandle
|
||||
);
|
||||
|
||||
/**
|
||||
This function is to convert UINTN to ASCII string with the required formatting.
|
||||
|
||||
@param[in] Number Numeric value to be converted.
|
||||
@param[in] Buffer The pointer to the buffer for ASCII string.
|
||||
@param[in] Length The length of the required format.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootUintnToAscDecWithFormat (
|
||||
IN UINTN Number,
|
||||
IN UINT8 *Buffer,
|
||||
IN INTN Length
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
This function is to display the IPv4 address.
|
||||
|
||||
@param[in] Ip The pointer to the IPv4 address.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootShowIp4Addr (
|
||||
IN EFI_IPv4_ADDRESS *Ip
|
||||
);
|
||||
|
||||
//
|
||||
// A wrapper structure to hold the HTTP headers.
|
||||
//
|
||||
typedef struct {
|
||||
UINTN MaxHeaderCount;
|
||||
UINTN HeaderCount;
|
||||
EFI_HTTP_HEADER *Headers;
|
||||
} HTTP_IO_HEADER;
|
||||
|
||||
/**
|
||||
Create a HTTP_IO_HEADER to hold the HTTP header items.
|
||||
|
||||
@param[in] MaxHeaderCount The maximun number of HTTP header in this holder.
|
||||
|
||||
@return A pointer of the HTTP header holder or NULL if failed.
|
||||
|
||||
**/
|
||||
HTTP_IO_HEADER *
|
||||
HttpBootCreateHeader (
|
||||
IN UINTN MaxHeaderCount
|
||||
);
|
||||
|
||||
/**
|
||||
Destroy the HTTP_IO_HEADER and release the resouces.
|
||||
|
||||
@param[in] HttpIoHeader Point to the HTTP header holder to be destroyed.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpBootFreeHeader (
|
||||
IN HTTP_IO_HEADER *HttpIoHeader
|
||||
);
|
||||
|
||||
/**
|
||||
Set or update a HTTP header with the field name and corresponding value.
|
||||
|
||||
@param[in] HttpIoHeader Point to the HTTP header holder.
|
||||
@param[in] FieldName Null terminated string which describes a field name.
|
||||
@param[in] FieldValue Null terminated string which describes the corresponding field value.
|
||||
|
||||
@retval EFI_SUCCESS The HTTP header has been set or updated.
|
||||
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
|
||||
@retval EFI_OUT_OF_RESOURCES Insufficient resource to complete the operation.
|
||||
@retval Other Unexpected error happened.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpBootSetHeader (
|
||||
IN HTTP_IO_HEADER *HttpIoHeader,
|
||||
IN CHAR8 *FieldName,
|
||||
IN CHAR8 *FieldValue
|
||||
);
|
||||
|
||||
//
|
||||
// HTTP_IO configuration data for IPv4
|
||||
//
|
||||
typedef struct {
|
||||
EFI_HTTP_VERSION HttpVersion;
|
||||
UINT32 RequestTimeOut; // In milliseconds.
|
||||
UINT32 ResponseTimeOut; // In milliseconds.
|
||||
BOOLEAN UseDefaultAddress;
|
||||
EFI_IPv4_ADDRESS LocalIp;
|
||||
EFI_IPv4_ADDRESS SubnetMask;
|
||||
UINT16 LocalPort;
|
||||
} HTTP4_IO_CONFIG_DATA;
|
||||
|
||||
//
|
||||
// HTTP_IO configuration
|
||||
//
|
||||
typedef union {
|
||||
HTTP4_IO_CONFIG_DATA Config4;
|
||||
} HTTP_IO_CONFIG_DATA;
|
||||
|
||||
//
|
||||
// HTTO_IO wrapper of the EFI HTTP service.
|
||||
//
|
||||
typedef struct {
|
||||
UINT8 IpVersion;
|
||||
EFI_HANDLE Image;
|
||||
EFI_HANDLE Controller;
|
||||
EFI_HANDLE Handle;
|
||||
|
||||
EFI_HTTP_PROTOCOL *Http;
|
||||
|
||||
EFI_HTTP_TOKEN ReqToken;
|
||||
EFI_HTTP_MESSAGE ReqMessage;
|
||||
EFI_HTTP_TOKEN RspToken;
|
||||
EFI_HTTP_MESSAGE RspMessage;
|
||||
|
||||
BOOLEAN IsTxDone;
|
||||
BOOLEAN IsRxDone;
|
||||
} HTTP_IO;
|
||||
|
||||
//
|
||||
// A wrapper structure to hold the received HTTP response data.
|
||||
//
|
||||
typedef struct {
|
||||
EFI_HTTP_RESPONSE_DATA Response;
|
||||
UINTN HeaderCount;
|
||||
EFI_HTTP_HEADER *Headers;
|
||||
UINTN BodyLength;
|
||||
CHAR8 *Body;
|
||||
} HTTP_IO_RESOPNSE_DATA;
|
||||
|
||||
/**
|
||||
Create a HTTP_IO to access the HTTP service. It will create and configure
|
||||
a HTTP child handle.
|
||||
|
||||
@param[in] Image The handle of the driver image.
|
||||
@param[in] Controller The handle of the controller.
|
||||
@param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
|
||||
@param[in] ConfigData The HTTP_IO configuration data.
|
||||
@param[out] HttpIo The HTTP_IO.
|
||||
|
||||
@retval EFI_SUCCESS The HTTP_IO is created and configured.
|
||||
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
||||
@retval EFI_UNSUPPORTED One or more of the control options are not
|
||||
supported in the implementation.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
@retval Others Failed to create the HTTP_IO or configure it.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpIoCreateIo (
|
||||
IN EFI_HANDLE Image,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN UINT8 IpVersion,
|
||||
IN HTTP_IO_CONFIG_DATA *ConfigData,
|
||||
OUT HTTP_IO *HttpIo
|
||||
);
|
||||
|
||||
/**
|
||||
Destroy the HTTP_IO and release the resouces.
|
||||
|
||||
@param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed.
|
||||
|
||||
**/
|
||||
VOID
|
||||
HttpIoDestroyIo (
|
||||
IN HTTP_IO *HttpIo
|
||||
);
|
||||
|
||||
/**
|
||||
Synchronously send a HTTP REQUEST message to the server.
|
||||
|
||||
@param[in] HttpIo The HttpIo wrapping the HTTP service.
|
||||
@param[in] Request A pointer to storage such data as URL and HTTP method.
|
||||
@param[in] HeaderCount Number of HTTP header structures in Headers list.
|
||||
@param[in] Headers Array containing list of HTTP headers.
|
||||
@param[in] BodyLength Length in bytes of the HTTP body.
|
||||
@param[in] Body Body associated with the HTTP request.
|
||||
|
||||
@retval EFI_SUCCESS The HTTP request is trasmitted.
|
||||
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
@retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
|
||||
@retval Others Other errors as indicated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpIoSendRequest (
|
||||
IN HTTP_IO *HttpIo,
|
||||
IN EFI_HTTP_REQUEST_DATA *Request, OPTIONAL
|
||||
IN UINTN HeaderCount,
|
||||
IN EFI_HTTP_HEADER *Headers, OPTIONAL
|
||||
IN UINTN BodyLength,
|
||||
IN VOID *Body OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
Synchronously receive a HTTP RESPONSE message from the server.
|
||||
|
||||
@param[in] HttpIo The HttpIo wrapping the HTTP service.
|
||||
@param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header).
|
||||
FALSE to continue receive the previous response message.
|
||||
@param[out] ResponseData Point to a wrapper of the received response data.
|
||||
|
||||
@retval EFI_SUCCESS The HTTP resopnse is received.
|
||||
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
@retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
|
||||
@retval Others Other errors as indicated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
HttpIoRecvResponse (
|
||||
IN HTTP_IO *HttpIo,
|
||||
IN BOOLEAN RecvMsgHeader,
|
||||
OUT HTTP_IO_RESOPNSE_DATA *ResponseData
|
||||
);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue