123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449 |
- /** @file
- Implementation of the boot file download function.
- Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
- (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "HttpBootDxe.h"
- /**
- 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 (
- IN HTTP_BOOT_PRIVATE_DATA *Private
- )
- {
- EFI_DEV_PATH *Node;
- EFI_DEVICE_PATH_PROTOCOL *TmpIpDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *TmpDnsDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
- UINTN Length;
- EFI_STATUS Status;
- TmpIpDevicePath = NULL;
- TmpDnsDevicePath = 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));
- } else {
- Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH));
- if (Node == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- Node->Ipv6.Header.Type = MESSAGING_DEVICE_PATH;
- Node->Ipv6.Header.SubType = MSG_IPv6_DP;
- 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.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));
- }
- TmpIpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)Node);
- FreePool (Node);
- 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) {
- 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));
- 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);
- if (NewDevicePath == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- if (!Private->UsingIpv6) {
- //
- // Reinstall the device path protocol of the child handle.
- //
- Status = gBS->ReinstallProtocolInterface (
- Private->Ip4Nic->Controller,
- &gEfiDevicePathProtocolGuid,
- Private->Ip4Nic->DevicePath,
- NewDevicePath
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- FreePool (Private->Ip4Nic->DevicePath);
- Private->Ip4Nic->DevicePath = NewDevicePath;
- } else {
- //
- // Reinstall the device path protocol of the child handle.
- //
- Status = gBS->ReinstallProtocolInterface (
- Private->Ip6Nic->Controller,
- &gEfiDevicePathProtocolGuid,
- Private->Ip6Nic->DevicePath,
- NewDevicePath
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- FreePool (Private->Ip6Nic->DevicePath);
- Private->Ip6Nic->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
- HttpBootDhcp4ExtractUriInfo (
- IN HTTP_BOOT_PRIVATE_DATA *Private
- )
- {
- HTTP_BOOT_DHCP4_PACKET_CACHE *SelectOffer;
- HTTP_BOOT_DHCP4_PACKET_CACHE *HttpOffer;
- UINT32 SelectIndex;
- UINT32 ProxyIndex;
- UINT32 DnsServerIndex;
- 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);
- DnsServerIndex = 0;
- 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 (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 {
- //
- // 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 ((DEBUG_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;
- }
- }
- //
- // Extract the port from URL, and use default HTTP port 80 if not provided.
- //
- Status = HttpUrlGetPort (
- Private->BootFileUri,
- Private->BootFileUriParser,
- &Private->Port
- );
- if (EFI_ERROR (Status) || (Private->Port == 0)) {
- Private->Port = 80;
- }
- //
- // All boot informations are valid here.
- //
- //
- // 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;
- }
- /**
- Parse the boot file URI information from the selected Dhcp6 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
- HttpBootDhcp6ExtractUriInfo (
- IN HTTP_BOOT_PRIVATE_DATA *Private
- )
- {
- HTTP_BOOT_DHCP6_PACKET_CACHE *SelectOffer;
- 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;
- ASSERT (Private != NULL);
- ASSERT (Private->SelectIndex != 0);
- SelectIndex = Private->SelectIndex - 1;
- ASSERT (SelectIndex < HTTP_BOOT_OFFER_MAX_NUM);
- DnsServerIndex = 0;
- Status = EFI_SUCCESS;
- HostName = NULL;
- //
- // SelectOffer contains the IP address configuration and name server configuration.
- // HttpOffer contains the boot file URL.
- //
- SelectOffer = &Private->OfferBuffer[SelectIndex].Dhcp6;
- 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 {
- //
- // 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 ((DEBUG_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;
- }
- //
- // Set the Local station address to IP layer.
- //
- Status = HttpBootSetIp6Address (Private);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Register the IPv6 gateway address to the network device.
- //
- 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)) {
- goto Error;
- }
- }
- //
- // 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 (
- Private->BootFileUri,
- Private->BootFileUriParser,
- &IpAddr
- );
- if (EFI_ERROR (Status)) {
- //
- // The Http server address is expressed by Name Ip, so perform DNS resolution
- //
- Status = HttpUrlGetHostName (
- Private->BootFileUri,
- Private->BootFileUriParser,
- &HostName
- );
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- HostNameSize = AsciiStrSize (HostName);
- HostNameStr = AllocateZeroPool (HostNameSize * sizeof (CHAR16));
- if (HostNameStr == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
- 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));
- //
- // Extract the port from URL, and use default HTTP port 80 if not provided.
- //
- Status = HttpUrlGetPort (
- Private->BootFileUri,
- Private->BootFileUriParser,
- &Private->Port
- );
- if (EFI_ERROR (Status) || (Private->Port == 0)) {
- Private->Port = 80;
- }
- //
- // All boot informations are valid here.
- //
- //
- // Update the device path to include the boot resource information.
- //
- Status = HttpBootUpdateDevicePath (Private);
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- return Status;
- Error:
- if (Private->DnsServerIp != NULL) {
- FreePool (Private->DnsServerIp);
- Private->DnsServerIp = NULL;
- }
- 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 = HttpBootDhcp4ExtractUriInfo (Private);
- } else {
- Status = HttpBootDhcp6ExtractUriInfo (Private);
- }
- 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.
- @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;
- EFI_HANDLE ImageHandle;
- UINT32 TimeoutValue;
- ASSERT (Private != NULL);
- //
- // Get HTTP timeout value
- //
- TimeoutValue = PcdGet32 (PcdHttpIoTimeout);
- ZeroMem (&ConfigData, sizeof (HTTP_IO_CONFIG_DATA));
- if (!Private->UsingIpv6) {
- ConfigData.Config4.HttpVersion = HttpVersion11;
- ConfigData.Config4.RequestTimeOut = TimeoutValue;
- 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 = TimeoutValue;
- IP6_COPY_ADDRESS (&ConfigData.Config6.LocalIp, &Private->StationIp.v6);
- ImageHandle = Private->Ip6Nic->ImageHandle;
- }
- Status = HttpIoCreateIo (
- ImageHandle,
- Private->Controller,
- Private->UsingIpv6 ? IP_VERSION_6 : IP_VERSION_4,
- &ConfigData,
- HttpBootHttpIoCallback,
- (VOID *)Private,
- &Private->HttpIo
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Private->HttpCreated = TRUE;
- return EFI_SUCCESS;
- }
- /**
- 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);
- }
- }
- /**
- 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.
- 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;
- EFI_STATUS Status;
- EFI_HTTP_BOOT_CALLBACK_PROTOCOL *HttpBootCallback;
- //
- // We only care about the entity data.
- //
- if (EventType != BodyParseEventOnData) {
- return EFI_SUCCESS;
- }
- 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.
- //
- 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);
- }
- //
- // The caller doesn't provide a buffer, save the block into cache list.
- //
- if (CallbackData->Cache != NULL) {
- 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);
- }
- 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.
- @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.
- @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 EFI_ACCESS_DENIED The server needs to authenticate the client.
- @retval Others Unexpected error happened.
- **/
- EFI_STATUS
- HttpBootGetBootFile (
- IN HTTP_BOOT_PRIVATE_DATA *Private,
- IN BOOLEAN HeaderOnly,
- IN OUT UINTN *BufferSize,
- 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_RESPONSE_DATA *ResponseData;
- HTTP_IO_RESPONSE_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;
- UINTN UrlSize;
- CHAR16 *Url;
- BOOLEAN IdentityMode;
- UINTN ReceivedSize;
- CHAR8 BaseAuthValue[80];
- EFI_HTTP_HEADER *HttpHeader;
- CHAR8 *Data;
- ASSERT (Private != NULL);
- ASSERT (Private->HttpCreated);
- if ((BufferSize == NULL) || (ImageType == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- if ((*BufferSize != 0) && (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // First, check whether we already cached the requested Uri.
- //
- UrlSize = AsciiStrSize (Private->BootFileUri);
- Url = AllocatePool (UrlSize * sizeof (CHAR16));
- if (Url == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- 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;
- }
- }
- //
- // Not found in cache, try to download it through HTTP.
- //
- //
- // 1. Create a temp cache item for the requested URI if caller doesn't provide buffer.
- //
- Cache = NULL;
- if ((!HeaderOnly) && (*BufferSize == 0)) {
- Cache = AllocateZeroPool (sizeof (HTTP_BOOT_CACHE_CONTENT));
- if (Cache == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ERROR_1;
- }
- Cache->ImageType = ImageTypeMax;
- 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
- // [Authorization]
- //
- HttpIoHeader = HttpIoCreateHeader ((Private->AuthData != NULL) ? 4 : 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 = HttpIoSetHeader (
- HttpIoHeader,
- HTTP_HEADER_HOST,
- HostName
- );
- FreePool (HostName);
- if (EFI_ERROR (Status)) {
- goto ERROR_3;
- }
- //
- // Add HTTP header field 2: Accept
- //
- Status = HttpIoSetHeader (
- HttpIoHeader,
- HTTP_HEADER_ACCEPT,
- "*/*"
- );
- if (EFI_ERROR (Status)) {
- goto ERROR_3;
- }
- //
- // Add HTTP header field 3: User-Agent
- //
- Status = HttpIoSetHeader (
- HttpIoHeader,
- HTTP_HEADER_USER_AGENT,
- HTTP_USER_AGENT_EFI_HTTP_BOOT
- );
- if (EFI_ERROR (Status)) {
- goto ERROR_3;
- }
- //
- // Add HTTP header field 4: Authorization
- //
- if (Private->AuthData != NULL) {
- ASSERT (HttpIoHeader->MaxHeaderCount == 4);
- if ((Private->AuthScheme != NULL) && (CompareMem (Private->AuthScheme, "Basic", 5) != 0)) {
- Status = EFI_UNSUPPORTED;
- goto ERROR_3;
- }
- AsciiSPrint (
- BaseAuthValue,
- sizeof (BaseAuthValue),
- "%a %a",
- "Basic",
- Private->AuthData
- );
- Status = HttpIoSetHeader (
- HttpIoHeader,
- HTTP_HEADER_AUTHORIZATION,
- BaseAuthValue
- );
- 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;
- //
- // 2.3 Record the request info in a temp cache item.
- //
- if (Cache != NULL) {
- 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_RESPONSE_DATA));
- if (ResponseData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ERROR_4;
- }
- Data = NULL;
- Status = HttpIoRecvResponse (
- &Private->HttpIo,
- 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;
- if ((StatusCode == HTTP_STATUS_401_UNAUTHORIZED) || \
- (StatusCode == HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED))
- {
- if ((Private->AuthData != NULL) || (Private->AuthScheme != NULL)) {
- if (Private->AuthData != NULL) {
- FreePool (Private->AuthData);
- Private->AuthData = NULL;
- }
- if (Private->AuthScheme != NULL) {
- FreePool (Private->AuthScheme);
- Private->AuthScheme = NULL;
- }
- Status = EFI_ACCESS_DENIED;
- goto ERROR_4;
- }
- //
- // Server indicates the user has to provide a user-id and password as a means of identification.
- //
- if (Private->HttpBootCallback != NULL) {
- Data = AllocateZeroPool (sizeof (CHAR8) * HTTP_BOOT_AUTHENTICATION_INFO_MAX_LEN);
- if (Data == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ERROR_4;
- }
- Status = Private->HttpBootCallback->Callback (
- Private->HttpBootCallback,
- HttpBootHttpAuthInfo,
- TRUE,
- HTTP_BOOT_AUTHENTICATION_INFO_MAX_LEN,
- Data
- );
- if (EFI_ERROR (Status)) {
- if (Data != NULL) {
- FreePool (Data);
- }
- goto ERROR_5;
- }
- Private->AuthData = (CHAR8 *)Data;
- }
- HttpHeader = HttpFindHeader (
- ResponseData->HeaderCount,
- ResponseData->Headers,
- HTTP_HEADER_WWW_AUTHENTICATE
- );
- if (HttpHeader != NULL) {
- Private->AuthScheme = AllocateZeroPool (AsciiStrLen (HttpHeader->FieldValue) + 1);
- if (Private->AuthScheme == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- CopyMem (Private->AuthScheme, HttpHeader->FieldValue, AsciiStrLen (HttpHeader->FieldValue));
- }
- Status = EFI_ACCESS_DENIED;
- }
- }
- 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;
- }
- //
- // 3.2 Cache the response header.
- //
- if (Cache != NULL) {
- Cache->ResponseData = ResponseData;
- Cache->ImageType = *ImageType;
- }
- //
- // 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;
- Context.Private = Private;
- 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.
- //
- Block = NULL;
- if (!HeaderOnly) {
- //
- // 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) {
- //
- // In identity transfer-coding there is no need to parse the message body,
- // just download the message body to the user provided buffer directly.
- //
- 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;
- }
- 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 {
- //
- // In "chunked" transfer-coding mode, so we need to parse the received
- // data to get the real entity content.
- //
- 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, we should be able to get the file size now.
- //
- Status = HttpGetEntityLength (Parser, &ContentLength);
- if (EFI_ERROR (Status)) {
- goto ERROR_6;
- }
- if (*BufferSize < ContentLength) {
- Status = EFI_BUFFER_TOO_SMALL;
- } else {
- Status = EFI_SUCCESS;
- }
- *BufferSize = ContentLength;
- //
- // 4. Save the cache item to driver's cache list and return.
- //
- if (Cache != NULL) {
- Cache->EntityLength = ContentLength;
- InsertTailList (&Private->CacheList, &Cache->Link);
- }
- if (Parser != NULL) {
- HttpFreeMsgParser (Parser);
- }
- return Status;
- 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:
- HttpIoFreeHeader (HttpIoHeader);
- ERROR_2:
- if (Cache != NULL) {
- FreePool (Cache);
- }
- ERROR_1:
- if (Url != NULL) {
- FreePool (Url);
- }
- return Status;
- }
|