X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=NetworkPkg%2FHttpBootDxe%2FHttpBootClient.c;h=90a6acb0d4ed4203e154c04289e1e9635c0d0fe8;hp=b81b03c96070400db493e148f53ebfcb1e4cb2a4;hb=f33d5d68abc02727dc828c1079e72ab65e1d63af;hpb=b659408b933f40765960e877de3e1f8ceaab52cb
diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.c b/NetworkPkg/HttpBootDxe/HttpBootClient.c
index b81b03c960..90a6acb0d4 100644
--- a/NetworkPkg/HttpBootDxe/HttpBootClient.c
+++ b/NetworkPkg/HttpBootDxe/HttpBootClient.c
@@ -1,13 +1,14 @@
/** @file
Implementation of the boot file download function.
-Copyright (c) 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials are licensed and made available under
-the terms and conditions of the BSD License that accompanies this distribution.
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP
+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,
+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.
**/
@@ -15,14 +16,14 @@ 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.
+ Update the 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 (
@@ -30,13 +31,15 @@ HttpBootUpdateDevicePath (
)
{
EFI_DEV_PATH *Node;
- EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TmpIpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TmpDnsDevicePath;
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
UINTN Length;
EFI_STATUS Status;
- TmpDevicePath = NULL;
-
+ TmpIpDevicePath = NULL;
+ TmpDnsDevicePath = NULL;
+
//
// Update the IP node with DHCP assigned information.
//
@@ -64,36 +67,72 @@ HttpBootUpdateDevicePath (
SetDevicePathNodeLength (Node, sizeof (IPv6_DEVICE_PATH));
Node->Ipv6.PrefixLength = IP6_PREFIX_LENGTH;
Node->Ipv6.RemotePort = Private->Port;
- Node->Ipv6.Protocol = EFI_IP_PROTO_TCP;
+ Node->Ipv6.Protocol = EFI_IP_PROTO_TCP;
Node->Ipv6.IpAddressOrigin = 0;
CopyMem (&Node->Ipv6.LocalIpAddress, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
CopyMem (&Node->Ipv6.RemoteIpAddress, &Private->ServerIp.v6, sizeof (EFI_IPv6_ADDRESS));
CopyMem (&Node->Ipv6.GatewayIpAddress, &Private->GatewayIp.v6, sizeof (EFI_IPv6_ADDRESS));
}
-
- TmpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
+
+ TmpIpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
FreePool (Node);
- if (TmpDevicePath == NULL) {
+ if (TmpIpDevicePath == NULL) {
return EFI_OUT_OF_RESOURCES;
}
+ //
+ // Update the DNS node with DNS server IP list if existed.
+ //
+ if (Private->DnsServerIp != NULL) {
+ Length = sizeof (EFI_DEVICE_PATH_PROTOCOL) + sizeof (Node->Dns.IsIPv6) + Private->DnsServerCount * sizeof (EFI_IP_ADDRESS);
+ Node = AllocatePool (Length);
+ if (Node == NULL) {
+ FreePool (TmpIpDevicePath);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Node->DevPath.Type = MESSAGING_DEVICE_PATH;
+ Node->DevPath.SubType = MSG_DNS_DP;
+ SetDevicePathNodeLength (Node, Length);
+ Node->Dns.IsIPv6 = Private->UsingIpv6 ? 0x01 : 0x00;
+ CopyMem ((UINT8*) Node + sizeof (EFI_DEVICE_PATH_PROTOCOL) + sizeof (Node->Dns.IsIPv6), Private->DnsServerIp, Private->DnsServerCount * sizeof (EFI_IP_ADDRESS));
+
+ TmpDnsDevicePath = AppendDevicePathNode (TmpIpDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
+ FreePool (Node);
+ FreePool (TmpIpDevicePath);
+ TmpIpDevicePath = NULL;
+ if (TmpDnsDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
//
// 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);
+ if (TmpIpDevicePath != NULL) {
+ FreePool (TmpIpDevicePath);
+ }
+ if (TmpDnsDevicePath != NULL) {
+ FreePool (TmpDnsDevicePath);
+ }
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);
+
+ if (TmpDnsDevicePath != NULL) {
+ NewDevicePath = AppendDevicePathNode (TmpDnsDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
+ FreePool (TmpDnsDevicePath);
+ } else {
+ ASSERT (TmpIpDevicePath != NULL);
+ NewDevicePath = AppendDevicePathNode (TmpIpDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
+ FreePool (TmpIpDevicePath);
+ }
FreePool (Node);
- FreePool (TmpDevicePath);
if (NewDevicePath == NULL) {
return EFI_OUT_OF_RESOURCES;
}
@@ -111,7 +150,7 @@ HttpBootUpdateDevicePath (
if (EFI_ERROR (Status)) {
return Status;
}
-
+
FreePool (Private->Ip4Nic->DevicePath);
Private->Ip4Nic->DevicePath = NewDevicePath;
} else {
@@ -130,7 +169,7 @@ HttpBootUpdateDevicePath (
FreePool (Private->Ip6Nic->DevicePath);
Private->Ip6Nic->DevicePath = NewDevicePath;
}
-
+
return EFI_SUCCESS;
}
@@ -152,6 +191,7 @@ HttpBootDhcp4ExtractUriInfo (
HTTP_BOOT_DHCP4_PACKET_CACHE *HttpOffer;
UINT32 SelectIndex;
UINT32 ProxyIndex;
+ UINT32 DnsServerIndex;
EFI_DHCP4_PACKET_OPTION *Option;
EFI_STATUS Status;
@@ -160,6 +200,8 @@ HttpBootDhcp4ExtractUriInfo (
SelectIndex = Private->SelectIndex - 1;
ASSERT (SelectIndex < HTTP_BOOT_OFFER_MAX_NUM);
+ DnsServerIndex = 0;
+
Status = EFI_SUCCESS;
//
@@ -167,26 +209,74 @@ HttpBootDhcp4ExtractUriInfo (
// HttpOffer contains the boot file URL.
//
SelectOffer = &Private->OfferBuffer[SelectIndex].Dhcp4;
- if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) || (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns)) {
- HttpOffer = SelectOffer;
+ if (Private->FilePathUri == NULL) {
+ //
+ // In Corporate environment, we need a HttpOffer.
+ //
+ if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) ||
+ (SelectOffer->OfferType == HttpOfferTypeDhcpIpUriDns) ||
+ (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns)) {
+ HttpOffer = SelectOffer;
+ } else {
+ ASSERT (Private->SelectProxyType != HttpOfferTypeMax);
+ ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
+ HttpOffer = &Private->OfferBuffer[ProxyIndex].Dhcp4;
+ }
+ Private->BootFileUriParser = HttpOffer->UriParser;
+ Private->BootFileUri = (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data;
} else {
- ASSERT (Private->SelectProxyType != HttpOfferTypeMax);
- ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
- HttpOffer = &Private->OfferBuffer[ProxyIndex].Dhcp4;
+ //
+ // In Home environment the BootFileUri comes from the FilePath.
+ //
+ Private->BootFileUriParser = Private->FilePathUriParser;
+ Private->BootFileUri = Private->FilePathUri;
}
//
- // Configure the default DNS server if server assigned.
+ // Check the URI scheme.
//
- if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) || (SelectOffer->OfferType == HttpOfferTypeDhcpDns)) {
+ Status = HttpBootCheckUriScheme (Private->BootFileUri);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "HttpBootDhcp4ExtractUriInfo: %r.\n", Status));
+ if (Status == EFI_INVALID_PARAMETER) {
+ AsciiPrint ("\n Error: Invalid URI address.\n");
+ } else if (Status == EFI_ACCESS_DENIED) {
+ AsciiPrint ("\n Error: Access forbidden, only HTTPS connection is allowed.\n");
+ }
+ return Status;
+ }
+
+ if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) ||
+ (SelectOffer->OfferType == HttpOfferTypeDhcpDns) ||
+ (SelectOffer->OfferType == HttpOfferTypeDhcpIpUriDns)) {
Option = SelectOffer->OptList[HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER];
ASSERT (Option != NULL);
+
+ //
+ // Record the Dns Server address list.
+ //
+ Private->DnsServerCount = (Option->Length) / sizeof (EFI_IPv4_ADDRESS);
+
+ Private->DnsServerIp = AllocateZeroPool (Private->DnsServerCount * sizeof (EFI_IP_ADDRESS));
+ if (Private->DnsServerIp == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (DnsServerIndex = 0; DnsServerIndex < Private->DnsServerCount; DnsServerIndex++) {
+ CopyMem (&(Private->DnsServerIp[DnsServerIndex].v4), &(((EFI_IPv4_ADDRESS *) Option->Data)[DnsServerIndex]), sizeof (EFI_IPv4_ADDRESS));
+ }
+
+ //
+ // Configure the default DNS server if server assigned.
+ //
Status = HttpBootRegisterIp4Dns (
Private,
Option->Length,
Option->Data
);
if (EFI_ERROR (Status)) {
+ FreePool (Private->DnsServerIp);
+ Private->DnsServerIp = NULL;
return Status;
}
}
@@ -195,30 +285,26 @@ HttpBootDhcp4ExtractUriInfo (
// 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->BootFileUri,
+ Private->BootFileUriParser,
&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.
+ // Update the device path to include the boot resource information.
//
Status = HttpBootUpdateDevicePath (Private);
+ if (EFI_ERROR (Status) && Private->DnsServerIp != NULL) {
+ FreePool (Private->DnsServerIp);
+ Private->DnsServerIp = NULL;
+ }
return Status;
}
@@ -241,9 +327,11 @@ HttpBootDhcp6ExtractUriInfo (
HTTP_BOOT_DHCP6_PACKET_CACHE *HttpOffer;
UINT32 SelectIndex;
UINT32 ProxyIndex;
+ UINT32 DnsServerIndex;
EFI_DHCP6_PACKET_OPTION *Option;
EFI_IPv6_ADDRESS IpAddr;
CHAR8 *HostName;
+ UINTN HostNameSize;
CHAR16 *HostNameStr;
EFI_STATUS Status;
@@ -252,6 +340,8 @@ HttpBootDhcp6ExtractUriInfo (
SelectIndex = Private->SelectIndex - 1;
ASSERT (SelectIndex < HTTP_BOOT_OFFER_MAX_NUM);
+ DnsServerIndex = 0;
+
Status = EFI_SUCCESS;
HostName = NULL;
//
@@ -259,12 +349,41 @@ HttpBootDhcp6ExtractUriInfo (
// HttpOffer contains the boot file URL.
//
SelectOffer = &Private->OfferBuffer[SelectIndex].Dhcp6;
- if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) || (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns)) {
- HttpOffer = SelectOffer;
+ if (Private->FilePathUri == NULL) {
+ //
+ // In Corporate environment, we need a HttpOffer.
+ //
+ if ((SelectOffer->OfferType == HttpOfferTypeDhcpIpUri) ||
+ (SelectOffer->OfferType == HttpOfferTypeDhcpIpUriDns) ||
+ (SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns)) {
+ HttpOffer = SelectOffer;
+ } else {
+ ASSERT (Private->SelectProxyType != HttpOfferTypeMax);
+ ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
+ HttpOffer = &Private->OfferBuffer[ProxyIndex].Dhcp6;
+ }
+ Private->BootFileUriParser = HttpOffer->UriParser;
+ Private->BootFileUri = (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data;
} else {
- ASSERT (Private->SelectProxyType != HttpOfferTypeMax);
- ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
- HttpOffer = &Private->OfferBuffer[ProxyIndex].Dhcp6;
+ //
+ // In Home environment the BootFileUri comes from the FilePath.
+ //
+ Private->BootFileUriParser = Private->FilePathUriParser;
+ Private->BootFileUri = Private->FilePathUri;
+ }
+
+ //
+ // Check the URI scheme.
+ //
+ Status = HttpBootCheckUriScheme (Private->BootFileUri);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "HttpBootDhcp6ExtractUriInfo: %r.\n", Status));
+ if (Status == EFI_INVALID_PARAMETER) {
+ AsciiPrint ("\n Error: Invalid URI address.\n");
+ } else if (Status == EFI_ACCESS_DENIED) {
+ AsciiPrint ("\n Error: Access forbidden, only HTTPS connection is allowed.\n");
+ }
+ return Status;
}
//
@@ -274,104 +393,126 @@ HttpBootDhcp6ExtractUriInfo (
if (EFI_ERROR (Status)) {
return Status;
}
-
+
//
- // Configure the default DNS server if server assigned.
+ // Register the IPv6 gateway address to the network device.
//
- if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) || (SelectOffer->OfferType == HttpOfferTypeDhcpDns)) {
+ Status = HttpBootSetIp6Gateway (Private);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((SelectOffer->OfferType == HttpOfferTypeDhcpNameUriDns) ||
+ (SelectOffer->OfferType == HttpOfferTypeDhcpDns) ||
+ (SelectOffer->OfferType == HttpOfferTypeDhcpIpUriDns)) {
Option = SelectOffer->OptList[HTTP_BOOT_DHCP6_IDX_DNS_SERVER];
ASSERT (Option != NULL);
+
+ //
+ // Record the Dns Server address list.
+ //
+ Private->DnsServerCount = HTONS (Option->OpLen) / sizeof (EFI_IPv6_ADDRESS);
+
+ Private->DnsServerIp = AllocateZeroPool (Private->DnsServerCount * sizeof (EFI_IP_ADDRESS));
+ if (Private->DnsServerIp == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (DnsServerIndex = 0; DnsServerIndex < Private->DnsServerCount; DnsServerIndex++) {
+ CopyMem (&(Private->DnsServerIp[DnsServerIndex].v6), &(((EFI_IPv6_ADDRESS *) Option->Data)[DnsServerIndex]), sizeof (EFI_IPv6_ADDRESS));
+ }
+
+ //
+ // Configure the default DNS server if server assigned.
+ //
Status = HttpBootSetIp6Dns (
Private,
HTONS (Option->OpLen),
Option->Data
);
if (EFI_ERROR (Status)) {
- return Status;
+ goto Error;
}
}
-
+
//
- // Extract the HTTP server Ip frome URL. This is used to Check route table
+ // Extract the HTTP server Ip from URL. This is used to Check route table
// whether can send message to HTTP Server Ip through the GateWay.
//
Status = HttpUrlGetIp6 (
- (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,
- HttpOffer->UriParser,
+ Private->BootFileUri,
+ Private->BootFileUriParser,
&IpAddr
);
-
+
if (EFI_ERROR (Status)) {
//
// The Http server address is expressed by Name Ip, so perform DNS resolution
//
Status = HttpUrlGetHostName (
- (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,
- HttpOffer->UriParser,
+ Private->BootFileUri,
+ Private->BootFileUriParser,
&HostName
);
if (EFI_ERROR (Status)) {
- return Status;
+ goto Error;
}
-
- HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16));
+
+ HostNameSize = AsciiStrSize (HostName);
+ HostNameStr = AllocateZeroPool (HostNameSize * sizeof (CHAR16));
if (HostNameStr == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
-
- AsciiStrToUnicodeStr (HostName, HostNameStr);
+
+ AsciiStrToUnicodeStrS (HostName, HostNameStr, HostNameSize);
+
+ if (HostName != NULL) {
+ FreePool (HostName);
+ }
+
Status = HttpBootDns (Private, HostNameStr, &IpAddr);
FreePool (HostNameStr);
if (EFI_ERROR (Status)) {
+ AsciiPrint ("\n Error: Could not retrieve the host address from DNS server.\n");
goto Error;
- }
- }
-
- CopyMem (&Private->ServerIp.v6, &IpAddr, sizeof (EFI_IPv6_ADDRESS));
-
- //
- // register the IPv6 gateway address to the network device.
- //
- Status = HttpBootSetIp6Gateway (Private);
- if (EFI_ERROR (Status)) {
- return Status;
+ }
}
-
+
+ CopyMem (&Private->ServerIp.v6, &IpAddr, sizeof (EFI_IPv6_ADDRESS));
+
//
// Extract the port from URL, and use default HTTP port 80 if not provided.
//
Status = HttpUrlGetPort (
- (CHAR8*) HttpOffer->OptList[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,
- HttpOffer->UriParser,
+ Private->BootFileUri,
+ Private->BootFileUriParser,
&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_DHCP6_IDX_BOOT_FILE_URL]->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.
+ // Update the device path to include the boot resource information.
//
Status = HttpBootUpdateDevicePath (Private);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ return Status;
Error:
-
- if (HostName != NULL) {
- FreePool (HostName);
+ if (Private->DnsServerIp != NULL) {
+ FreePool (Private->DnsServerIp);
+ Private->DnsServerIp = NULL;
}
-
+
return Status;
}
@@ -391,7 +532,7 @@ HttpBootDiscoverBootInfo (
)
{
EFI_STATUS Status;
-
+
//
// Start D.O.R.A/S.A.R.R exchange to acquire station ip address and
// other Http boot information.
@@ -410,6 +551,40 @@ HttpBootDiscoverBootInfo (
return Status;
}
+/**
+ HttpIo Callback function which will be invoked when specified HTTP_IO_CALLBACK_EVENT happened.
+
+ @param[in] EventType Indicate the Event type that occurs in the current callback.
+ @param[in] Message HTTP message which will be send to, or just received from HTTP server.
+ @param[in] Context The Callback Context pointer.
+
+ @retval EFI_SUCCESS Tells the HttpIo to continue the HTTP process.
+ @retval Others Tells the HttpIo to abort the current HTTP process.
+**/
+EFI_STATUS
+EFIAPI
+HttpBootHttpIoCallback (
+ IN HTTP_IO_CALLBACK_EVENT EventType,
+ IN EFI_HTTP_MESSAGE *Message,
+ IN VOID *Context
+ )
+{
+ HTTP_BOOT_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ Private = (HTTP_BOOT_PRIVATE_DATA *) Context;
+ if (Private->HttpBootCallback != NULL) {
+ Status = Private->HttpBootCallback->Callback (
+ Private->HttpBootCallback,
+ EventType == HttpIoRequest ? HttpBootHttpRequest : HttpBootHttpResponse,
+ EventType == HttpIoRequest ? FALSE : TRUE,
+ sizeof (EFI_HTTP_MESSAGE),
+ (VOID *) Message
+ );
+ return Status;
+ }
+ return EFI_SUCCESS;
+}
+
/**
Create a HttpIo instance for the file download.
@@ -426,6 +601,7 @@ HttpBootCreateHttpIo (
{
HTTP_IO_CONFIG_DATA ConfigData;
EFI_STATUS Status;
+ EFI_HANDLE ImageHandle;
ASSERT (Private != NULL);
@@ -435,17 +611,21 @@ HttpBootCreateHttpIo (
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);
+ ImageHandle = Private->Ip4Nic->ImageHandle;
} else {
ConfigData.Config6.HttpVersion = HttpVersion11;
ConfigData.Config6.RequestTimeOut = HTTP_BOOT_REQUEST_TIMEOUT;
IP6_COPY_ADDRESS (&ConfigData.Config6.LocalIp, &Private->StationIp.v6);
+ ImageHandle = Private->Ip6Nic->ImageHandle;
}
Status = HttpIoCreateIo (
- Private->Image,
+ ImageHandle,
Private->Controller,
Private->UsingIpv6 ? IP_VERSION_6 : IP_VERSION_4,
&ConfigData,
+ HttpBootHttpIoCallback,
+ (VOID *) Private,
&Private->HttpIo
);
if (EFI_ERROR (Status)) {
@@ -456,81 +636,6 @@ HttpBootCreateHttpIo (
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.
@@ -601,7 +706,7 @@ HttpBootFreeCacheList (
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);
@@ -609,6 +714,87 @@ HttpBootFreeCacheList (
}
}
+/**
+ 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.
+ @param[out] ImageType The image type of the downloaded file.
+
+ @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,
+ OUT HTTP_BOOT_IMAGE_TYPE *ImageType
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Entry2;
+ HTTP_BOOT_CACHE_CONTENT *Cache;
+ HTTP_BOOT_ENTITY_DATA *EntityData;
+ UINTN CopyedSize;
+
+ if (Uri == NULL || BufferSize == NULL || Buffer == NULL || ImageType == 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 in cache, record image type.
+ //
+ *ImageType = Cache->ImageType;
+
+ //
+ // 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;
+}
+
/**
A callback function to intercept events during message parser.
@@ -622,7 +808,7 @@ HttpBootFreeCacheList (
@retval EFI_SUCCESS Continue to parser the message body.
@retval Others Abort the parse.
-
+
**/
EFI_STATUS
EFIAPI
@@ -635,6 +821,8 @@ HttpBootGetBootFileCallback (
{
HTTP_BOOT_CALLBACK_DATA *CallbackData;
HTTP_BOOT_ENTITY_DATA *NewEntityData;
+ EFI_STATUS Status;
+ EFI_HTTP_BOOT_CALLBACK_PROTOCOL *HttpBootCallback;
//
// We only care about the entity data.
@@ -644,6 +832,19 @@ HttpBootGetBootFileCallback (
}
CallbackData = (HTTP_BOOT_CALLBACK_DATA *) Context;
+ HttpBootCallback = CallbackData->Private->HttpBootCallback;
+ if (HttpBootCallback != NULL) {
+ Status = HttpBootCallback->Callback (
+ HttpBootCallback,
+ HttpBootHttpEntityBody,
+ TRUE,
+ (UINT32)Length,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
//
// Copy data if caller has provided a buffer.
//
@@ -677,7 +878,7 @@ HttpBootGetBootFileCallback (
/**
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.
@@ -688,6 +889,7 @@ HttpBootGetBootFileCallback (
@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.
+ @param[out] ImageType The image type of the downloaded file.
@retval EFI_SUCCESS The file was loaded.
@retval EFI_INVALID_PARAMETER BufferSize is NULL or Buffer Size is not NULL but Buffer is NULL.
@@ -703,14 +905,16 @@ HttpBootGetBootFile (
IN HTTP_BOOT_PRIVATE_DATA *Private,
IN BOOLEAN HeaderOnly,
IN OUT UINTN *BufferSize,
- OUT UINT8 *Buffer
+ OUT UINT8 *Buffer,
+ OUT HTTP_BOOT_IMAGE_TYPE *ImageType
)
{
EFI_STATUS Status;
+ EFI_HTTP_STATUS_CODE StatusCode;
CHAR8 *HostName;
EFI_HTTP_REQUEST_DATA *RequestData;
- HTTP_IO_RESOPNSE_DATA *ResponseData;
- HTTP_IO_RESOPNSE_DATA ResponseBody;
+ HTTP_IO_RESPONSE_DATA *ResponseData;
+ HTTP_IO_RESPONSE_DATA ResponseBody;
HTTP_IO *HttpIo;
HTTP_IO_HEADER *HttpIoHeader;
VOID *Parser;
@@ -718,12 +922,15 @@ HttpBootGetBootFile (
UINTN ContentLength;
HTTP_BOOT_CACHE_CONTENT *Cache;
UINT8 *Block;
+ UINTN UrlSize;
CHAR16 *Url;
-
+ BOOLEAN IdentityMode;
+ UINTN ReceivedSize;
+
ASSERT (Private != NULL);
ASSERT (Private->HttpCreated);
- if (BufferSize == NULL) {
+ if (BufferSize == NULL || ImageType == NULL) {
return EFI_INVALID_PARAMETER;
}
@@ -734,13 +941,14 @@ HttpBootGetBootFile (
//
// First, check whether we already cached the requested Uri.
//
- Url = AllocatePool ((AsciiStrLen (Private->BootFileUri) + 1) * sizeof (CHAR16));
+ UrlSize = AsciiStrSize (Private->BootFileUri);
+ Url = AllocatePool (UrlSize * sizeof (CHAR16));
if (Url == NULL) {
return EFI_OUT_OF_RESOURCES;
}
- AsciiStrToUnicodeStr (Private->BootFileUri, Url);
- if (!HeaderOnly) {
- Status = HttpBootGetFileFromCache (Private, Url, BufferSize, Buffer);
+ AsciiStrToUnicodeStrS (Private->BootFileUri, Url, UrlSize);
+ if (!HeaderOnly && Buffer != NULL) {
+ Status = HttpBootGetFileFromCache (Private, Url, BufferSize, Buffer, ImageType);
if (Status != EFI_NOT_FOUND) {
FreePool (Url);
return Status;
@@ -761,6 +969,7 @@ HttpBootGetBootFile (
Status = EFI_OUT_OF_RESOURCES;
goto ERROR_1;
}
+ Cache->ImageType = ImageTypeMax;
InitializeListHead (&Cache->EntityDataList);
}
@@ -794,7 +1003,7 @@ HttpBootGetBootFile (
}
Status = HttpBootSetHeader (
HttpIoHeader,
- HTTP_FIELD_NAME_HOST,
+ HTTP_HEADER_HOST,
HostName
);
FreePool (HostName);
@@ -807,7 +1016,7 @@ HttpBootGetBootFile (
//
Status = HttpBootSetHeader (
HttpIoHeader,
- HTTP_FIELD_NAME_ACCEPT,
+ HTTP_HEADER_ACCEPT,
"*/*"
);
if (EFI_ERROR (Status)) {
@@ -819,7 +1028,7 @@ HttpBootGetBootFile (
//
Status = HttpBootSetHeader (
HttpIoHeader,
- HTTP_FIELD_NAME_USER_AGENT,
+ HTTP_HEADER_USER_AGENT,
HTTP_USER_AGENT_EFI_HTTP_BOOT
);
if (EFI_ERROR (Status)) {
@@ -836,11 +1045,6 @@ HttpBootGetBootFile (
}
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.
@@ -872,7 +1076,7 @@ HttpBootGetBootFile (
//
// 3.1 First step, use zero BodyLength to only receive the response headers.
//
- ResponseData = AllocateZeroPool (sizeof(HTTP_IO_RESOPNSE_DATA));
+ ResponseData = AllocateZeroPool (sizeof(HTTP_IO_RESPONSE_DATA));
if (ResponseData == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ERROR_4;
@@ -882,6 +1086,25 @@ HttpBootGetBootFile (
TRUE,
ResponseData
);
+ if (EFI_ERROR (Status) || EFI_ERROR (ResponseData->Status)) {
+ if (EFI_ERROR (ResponseData->Status)) {
+ StatusCode = HttpIo->RspToken.Message->Data.Response->StatusCode;
+ HttpBootPrintErrorMessage (StatusCode);
+ Status = ResponseData->Status;
+ }
+ goto ERROR_5;
+ }
+
+ //
+ // Check the image type according to server's response.
+ //
+ Status = HttpBootCheckImageType (
+ Private->BootFileUri,
+ Private->BootFileUriParser,
+ ResponseData->HeaderCount,
+ ResponseData->Headers,
+ ImageType
+ );
if (EFI_ERROR (Status)) {
goto ERROR_5;
}
@@ -891,8 +1114,9 @@ HttpBootGetBootFile (
//
if (Cache != NULL) {
Cache->ResponseData = ResponseData;
+ Cache->ImageType = *ImageType;
}
-
+
//
// 3.3 Init a message-body parser from the header information.
//
@@ -903,8 +1127,9 @@ HttpBootGetBootFile (
Context.Buffer = Buffer;
Context.BufferSize = *BufferSize;
Context.Cache = Cache;
+ Context.Private = Private;
Status = HttpInitMsgParser (
- HeaderOnly? HttpMethodHead : HttpMethodGet,
+ HeaderOnly ? HttpMethodHead : HttpMethodGet,
ResponseData->Response.StatusCode,
ResponseData->HeaderCount,
ResponseData->Headers,
@@ -921,51 +1146,112 @@ HttpBootGetBootFile (
//
Block = NULL;
if (!HeaderOnly) {
- ZeroMem (&ResponseBody, sizeof (HTTP_IO_RESOPNSE_DATA));
- while (!HttpIsMessageComplete (Parser)) {
+ //
+ // 3.4.1, check whether we are in identity transfer-coding.
+ //
+ ContentLength = 0;
+ Status = HttpGetEntityLength (Parser, &ContentLength);
+ if (!EFI_ERROR (Status)) {
+ IdentityMode = TRUE;
+ } else {
+ IdentityMode = FALSE;
+ }
+
+ //
+ // 3.4.2, start the message-body download, the identity and chunked transfer-coding
+ // is handled in different path here.
+ //
+ ZeroMem (&ResponseBody, sizeof (HTTP_IO_RESPONSE_DATA));
+ if (IdentityMode) {
//
- // Allocate a block to hold the message-body, if caller doesn't provide
- // a buffer, the block will be cached and we will allocate a new one here.
+ // In identity transfer-coding there is no need to parse the message body,
+ // just download the message body to the user provided buffer directly.
//
- if (Block == NULL || Context.BufferSize == 0) {
- Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE);
- if (Block == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
+ ReceivedSize = 0;
+ while (ReceivedSize < ContentLength) {
+ ResponseBody.Body = (CHAR8*) Buffer + ReceivedSize;
+ ResponseBody.BodyLength = *BufferSize - ReceivedSize;
+ Status = HttpIoRecvResponse (
+ &Private->HttpIo,
+ FALSE,
+ &ResponseBody
+ );
+ if (EFI_ERROR (Status) || EFI_ERROR (ResponseBody.Status)) {
+ if (EFI_ERROR (ResponseBody.Status)) {
+ Status = ResponseBody.Status;
+ }
goto ERROR_6;
}
- Context.NewBlock = TRUE;
- Context.Block = Block;
- } else {
- Context.NewBlock = FALSE;
- }
-
- ResponseBody.Body = (CHAR8*) Block;
- ResponseBody.BodyLength = HTTP_BOOT_BLOCK_SIZE;
- Status = HttpIoRecvResponse (
- &Private->HttpIo,
- FALSE,
- &ResponseBody
- );
- if (EFI_ERROR (Status)) {
- goto ERROR_6;
+ ReceivedSize += ResponseBody.BodyLength;
+ if (Private->HttpBootCallback != NULL) {
+ Status = Private->HttpBootCallback->Callback (
+ Private->HttpBootCallback,
+ HttpBootHttpEntityBody,
+ TRUE,
+ (UINT32)ResponseBody.BodyLength,
+ ResponseBody.Body
+ );
+ if (EFI_ERROR (Status)) {
+ goto ERROR_6;
+ }
+ }
}
-
+ } else {
//
- // Parse the new received block of the message-body, the block will be saved in cache.
+ // In "chunked" transfer-coding mode, so we need to parse the received
+ // data to get the real entity content.
//
- Status = HttpParseMessageBody (
- Parser,
- ResponseBody.BodyLength,
- ResponseBody.Body
- );
- if (EFI_ERROR (Status)) {
- goto ERROR_6;
+ Block = NULL;
+ while (!HttpIsMessageComplete (Parser)) {
+ //
+ // Allocate a buffer in Block to hold the message-body.
+ // If caller provides a buffer, this Block will be reused in every HttpIoRecvResponse().
+ // Otherwise a buffer, the buffer in Block will be cached and we should allocate a new before
+ // every HttpIoRecvResponse().
+ //
+ if (Block == NULL || Context.BufferSize == 0) {
+ Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE);
+ if (Block == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ERROR_6;
+ }
+ Context.NewBlock = TRUE;
+ Context.Block = Block;
+ } else {
+ Context.NewBlock = FALSE;
+ }
+
+ ResponseBody.Body = (CHAR8*) Block;
+ ResponseBody.BodyLength = HTTP_BOOT_BLOCK_SIZE;
+ Status = HttpIoRecvResponse (
+ &Private->HttpIo,
+ FALSE,
+ &ResponseBody
+ );
+ if (EFI_ERROR (Status) || EFI_ERROR (ResponseBody.Status)) {
+ if (EFI_ERROR (ResponseBody.Status)) {
+ Status = ResponseBody.Status;
+ }
+ goto ERROR_6;
+ }
+
+ //
+ // Parse the new received block of the message-body, the block will be saved in cache.
+ //
+ 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.
+ // 3.5 Message-body receive & parse is completed, we should be able to get the file size now.
//
Status = HttpGetEntityLength (Parser, &ContentLength);
if (EFI_ERROR (Status)) {
@@ -974,6 +1260,8 @@ HttpBootGetBootFile (
if (*BufferSize < ContentLength) {
Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ Status = EFI_SUCCESS;
}
*BufferSize = ContentLength;
@@ -989,8 +1277,8 @@ HttpBootGetBootFile (
HttpFreeMsgParser (Parser);
}
- return EFI_SUCCESS;
-
+ return Status;
+
ERROR_6:
if (Parser != NULL) {
HttpFreeMsgParser (Parser);
@@ -999,7 +1287,7 @@ ERROR_6:
FreePool (Context.Block);
}
HttpBootFreeCache (Cache);
-
+
ERROR_5:
if (ResponseData != NULL) {
FreePool (ResponseData);
@@ -1021,3 +1309,4 @@ ERROR_1:
return Status;
}
+