From d933e70a9761bf47941ac3d973cc5e7ee44da930 Mon Sep 17 00:00:00 2001 From: Jiaxin Wu Date: Thu, 27 Aug 2015 01:07:31 +0000 Subject: [PATCH] NetworkPkg: Convert the UNIX to DOS end of line format Convert the UNIX to DOS end of line format. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiaxin Wu git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18326 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpBootDxe/HttpBootClient.c | 1660 ++++++++--------- NetworkPkg/HttpBootDxe/HttpBootClient.h | 278 +-- .../HttpBootDxe/HttpBootComponentName.c | 360 ++-- .../HttpBootDxe/HttpBootComponentName.h | 198 +- NetworkPkg/HttpBootDxe/HttpBootDhcp4.c | 1658 ++++++++-------- NetworkPkg/HttpBootDxe/HttpBootDhcp4.h | 562 +++--- NetworkPkg/HttpBootDxe/HttpBootDxe.c | 1118 +++++------ NetworkPkg/HttpBootDxe/HttpBootDxe.h | 606 +++--- NetworkPkg/HttpBootDxe/HttpBootDxe.inf | 136 +- NetworkPkg/HttpBootDxe/HttpBootImpl.c | 728 ++++---- NetworkPkg/HttpBootDxe/HttpBootImpl.h | 100 +- NetworkPkg/HttpBootDxe/HttpBootSupport.c | 1180 ++++++------ NetworkPkg/HttpBootDxe/HttpBootSupport.h | 500 ++--- .../HttpUtilitiesDxe/HttpUtilitiesDxe.c | 252 +-- .../HttpUtilitiesDxe/HttpUtilitiesDxe.h | 424 ++--- .../HttpUtilitiesDxe/HttpUtilitiesDxe.inf | 102 +- .../HttpUtilitiesDxe/HttpUtilitiesImpl.c | 558 +++--- .../HttpUtilitiesDxe/HttpUtilitiesProtocol.c | 784 ++++---- 18 files changed, 5602 insertions(+), 5602 deletions(-) diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.c b/NetworkPkg/HttpBootDxe/HttpBootClient.c index 2bf28c2c4d..3b4afc396f 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootClient.c +++ b/NetworkPkg/HttpBootDxe/HttpBootClient.c @@ -1,830 +1,830 @@ -/** @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. -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; -} +/** @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. +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; +} diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.h b/NetworkPkg/HttpBootDxe/HttpBootClient.h index 3f6671333f..2dfafab936 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootClient.h +++ b/NetworkPkg/HttpBootDxe/HttpBootClient.h @@ -1,139 +1,139 @@ -/** @file - Declaration 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. -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 +/** @file + Declaration 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. +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 diff --git a/NetworkPkg/HttpBootDxe/HttpBootComponentName.c b/NetworkPkg/HttpBootDxe/HttpBootComponentName.c index 4e4a52a8fa..0708598c4f 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootComponentName.c +++ b/NetworkPkg/HttpBootDxe/HttpBootComponentName.c @@ -1,180 +1,180 @@ -/** @file - Implementation of EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL protocol. - -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. -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) - ); - -} +/** @file + Implementation of EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL protocol. + +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. +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) + ); + +} diff --git a/NetworkPkg/HttpBootDxe/HttpBootComponentName.h b/NetworkPkg/HttpBootDxe/HttpBootComponentName.h index 706fa8da5b..3fce9b75ab 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootComponentName.h +++ b/NetworkPkg/HttpBootDxe/HttpBootComponentName.h @@ -1,99 +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.
-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 +/** @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.
+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 diff --git a/NetworkPkg/HttpBootDxe/HttpBootDhcp4.c b/NetworkPkg/HttpBootDxe/HttpBootDhcp4.c index 7486d24ead..217c608233 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDhcp4.c +++ b/NetworkPkg/HttpBootDxe/HttpBootDhcp4.c @@ -1,829 +1,829 @@ -/** @file - Functions implementation related with DHCPv4 for HTTP boot driver. - -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. -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; -} +/** @file + Functions implementation related with DHCPv4 for HTTP boot driver. + +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. +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; +} diff --git a/NetworkPkg/HttpBootDxe/HttpBootDhcp4.h b/NetworkPkg/HttpBootDxe/HttpBootDhcp4.h index 47e07aaa85..200501666b 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDhcp4.h +++ b/NetworkPkg/HttpBootDxe/HttpBootDhcp4.h @@ -1,281 +1,281 @@ -/** @file - Functions declaration related with DHCPv4 for HTTP boot driver. - -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. -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 -#elif defined (MDE_CPU_EBC) -#define EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE 0x0011 -#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 { - // - // or - // - // - HttpOfferTypeDhcpIpUri, - // - // - // - HttpOfferTypeDhcpNameUriDns, - // - // - // - HttpOfferTypeDhcpDns, - // - // - // - HttpOfferTypeDhcpOnly, - // - // or - // - // - HttpOfferTypeProxyNameUri, - // - // or - // - // - HttpOfferTypeProxyIpUri, - // - // - // - 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 +/** @file + Functions declaration related with DHCPv4 for HTTP boot driver. + +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. +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 +#elif defined (MDE_CPU_EBC) +#define EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE 0x0011 +#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 { + // + // or + // + // + HttpOfferTypeDhcpIpUri, + // + // + // + HttpOfferTypeDhcpNameUriDns, + // + // + // + HttpOfferTypeDhcpDns, + // + // + // + HttpOfferTypeDhcpOnly, + // + // or + // + // + HttpOfferTypeProxyNameUri, + // + // or + // + // + HttpOfferTypeProxyIpUri, + // + // + // + 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 diff --git a/NetworkPkg/HttpBootDxe/HttpBootDxe.c b/NetworkPkg/HttpBootDxe/HttpBootDxe.c index 0d2c7abd30..49be59b8c8 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDxe.c +++ b/NetworkPkg/HttpBootDxe/HttpBootDxe.c @@ -1,559 +1,559 @@ -/** @file - Driver Binding functions implementation for UEFI HTTP boot. - -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. -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 - ); -} - +/** @file + Driver Binding functions implementation for UEFI HTTP boot. + +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. +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 + ); +} + diff --git a/NetworkPkg/HttpBootDxe/HttpBootDxe.h b/NetworkPkg/HttpBootDxe/HttpBootDxe.h index 8fce03df06..08415f6e0c 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDxe.h +++ b/NetworkPkg/HttpBootDxe/HttpBootDxe.h @@ -1,303 +1,303 @@ -/** @file - UEFI HTTP boot driver's private data structure and interfaces declaration. - -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. -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 - -// -// Libraries -// -#include -#include -#include -#include -#include -#include -#include -#include - -// -// UEFI Driver Model Protocols -// -#include -#include -#include - -// -// Consumed Protocols -// -#include -#include -#include -#include - -// -// Produced Protocols -// -#include - -// -// 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 +/** @file + UEFI HTTP boot driver's private data structure and interfaces declaration. + +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. +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 + +// +// Libraries +// +#include +#include +#include +#include +#include +#include +#include +#include + +// +// UEFI Driver Model Protocols +// +#include +#include +#include + +// +// Consumed Protocols +// +#include +#include +#include +#include + +// +// Produced Protocols +// +#include + +// +// 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 diff --git a/NetworkPkg/HttpBootDxe/HttpBootDxe.inf b/NetworkPkg/HttpBootDxe/HttpBootDxe.inf index a60830400c..18f8f796f0 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDxe.inf +++ b/NetworkPkg/HttpBootDxe/HttpBootDxe.inf @@ -1,68 +1,68 @@ -## @file -# This modules produce the Load File Protocol for UEFI HTTP boot. -# -# 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 -# 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 +## @file +# This modules produce the Load File Protocol for UEFI HTTP boot. +# +# 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 +# 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 diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.c b/NetworkPkg/HttpBootDxe/HttpBootImpl.c index 920761e331..eee63c21d3 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootImpl.c +++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.c @@ -1,364 +1,364 @@ -/** @file - The implementation of EFI_LOAD_FILE_PROTOCOL for UEFI HTTP boot. - -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. -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) { - // - // Stop and release the DHCP4 child. - // - Private->Dhcp4->Stop (Private->Dhcp4); - Private->Dhcp4->Configure (Private->Dhcp4, NULL); - - 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); - } else { - // - // Stop and release the DHCP4 child. - // - Private->Dhcp4->Stop (Private->Dhcp4); - Private->Dhcp4->Configure (Private->Dhcp4, NULL); - } - - return Status; -} - -/// -/// Load File Protocol instance -/// -GLOBAL_REMOVE_IF_UNREFERENCED -EFI_LOAD_FILE_PROTOCOL gHttpBootDxeLoadFile = { - HttpBootDxeLoadFile -}; +/** @file + The implementation of EFI_LOAD_FILE_PROTOCOL for UEFI HTTP boot. + +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. +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) { + // + // Stop and release the DHCP4 child. + // + Private->Dhcp4->Stop (Private->Dhcp4); + Private->Dhcp4->Configure (Private->Dhcp4, NULL); + + 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); + } else { + // + // Stop and release the DHCP4 child. + // + Private->Dhcp4->Stop (Private->Dhcp4); + Private->Dhcp4->Configure (Private->Dhcp4, NULL); + } + + return Status; +} + +/// +/// Load File Protocol instance +/// +GLOBAL_REMOVE_IF_UNREFERENCED +EFI_LOAD_FILE_PROTOCOL gHttpBootDxeLoadFile = { + HttpBootDxeLoadFile +}; diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.h b/NetworkPkg/HttpBootDxe/HttpBootImpl.h index 90742dd159..a2e9f5a328 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootImpl.h +++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.h @@ -1,50 +1,50 @@ -/** @file - The declaration of UEFI HTTP boot 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. -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 +/** @file + The declaration of UEFI HTTP boot 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. +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 diff --git a/NetworkPkg/HttpBootDxe/HttpBootSupport.c b/NetworkPkg/HttpBootDxe/HttpBootSupport.c index e21b50d066..761643141f 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootSupport.c +++ b/NetworkPkg/HttpBootDxe/HttpBootSupport.c @@ -1,590 +1,590 @@ -/** @file - Support functions implementation for UEFI HTTP boot driver. - -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. -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; -} +/** @file + Support functions implementation for UEFI HTTP boot driver. + +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. +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; +} diff --git a/NetworkPkg/HttpBootDxe/HttpBootSupport.h b/NetworkPkg/HttpBootDxe/HttpBootSupport.h index d1fa287920..bef80e81d8 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootSupport.h +++ b/NetworkPkg/HttpBootDxe/HttpBootSupport.h @@ -1,250 +1,250 @@ -/** @file - Support functions declaration for UEFI HTTP boot driver. - -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. -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 +/** @file + Support functions declaration for UEFI HTTP boot driver. + +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. +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 diff --git a/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.c b/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.c index 6bd5b6c6af..8c54874b9f 100644 --- a/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.c +++ b/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.c @@ -1,126 +1,126 @@ -/** @file - The DriverEntryPoint and Unload for HttpUtilities driver. - - 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 - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php. - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "HttpUtilitiesDxe.h" - - -/** - Unloads an image. - - @param ImageHandle Handle that identifies the image to be unloaded. - - @retval EFI_SUCCESS The image has been unloaded. - @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle. - -**/ -EFI_STATUS -EFIAPI -HttpUtilitiesDxeUnload ( - IN EFI_HANDLE ImageHandle - ) -{ - EFI_STATUS Status; - UINTN HandleNum; - EFI_HANDLE *HandleBuffer; - UINT32 Index; - EFI_HTTP_UTILITIES_PROTOCOL *HttpUtilitiesProtocol; - - - HandleBuffer = NULL; - - // - // Locate all the handles with HttpUtilities protocol. - // - Status = gBS->LocateHandleBuffer ( - ByProtocol, - &gEfiHttpUtilitiesProtocolGuid, - NULL, - &HandleNum, - &HandleBuffer - ); - if (EFI_ERROR (Status)) { - return Status; - } - - for (Index = 0; Index < HandleNum; Index++) { - // - // Firstly, find HttpUtilitiesProtocol interface - // - Status = gBS->OpenProtocol ( - HandleBuffer[Index], - &gEfiHttpUtilitiesProtocolGuid, - (VOID **) &HttpUtilitiesProtocol, - ImageHandle, - NULL, - EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL - ); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Then, uninstall HttpUtilities interface - // - Status = gBS->UninstallMultipleProtocolInterfaces ( - HandleBuffer[Index], - &gEfiHttpUtilitiesProtocolGuid, HttpUtilitiesProtocol, - NULL - ); - if (EFI_ERROR (Status)) { - return Status; - } - } - - 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 ImageHandle The firmware allocated handle for the UEFI image. - @param SystemTable A pointer to the EFI System Table. - - @retval EFI_SUCCESS The operation completed successfully. - @retval Others An unexpected error occurred. -**/ -EFI_STATUS -EFIAPI -HttpUtilitiesDxeDriverEntryPoint ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable - ) -{ - EFI_STATUS Status; - - EFI_HANDLE Handle; - - Handle = NULL; - - // - // Install the HttpUtilities Protocol onto Handle - // - Status = gBS->InstallMultipleProtocolInterfaces ( - &Handle, - &gEfiHttpUtilitiesProtocolGuid, - &mHttpUtilitiesProtocol, - NULL - ); - - return Status; -} - +/** @file + The DriverEntryPoint and Unload for HttpUtilities driver. + + 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 + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "HttpUtilitiesDxe.h" + + +/** + Unloads an image. + + @param ImageHandle Handle that identifies the image to be unloaded. + + @retval EFI_SUCCESS The image has been unloaded. + @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle. + +**/ +EFI_STATUS +EFIAPI +HttpUtilitiesDxeUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + UINTN HandleNum; + EFI_HANDLE *HandleBuffer; + UINT32 Index; + EFI_HTTP_UTILITIES_PROTOCOL *HttpUtilitiesProtocol; + + + HandleBuffer = NULL; + + // + // Locate all the handles with HttpUtilities protocol. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiHttpUtilitiesProtocolGuid, + NULL, + &HandleNum, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < HandleNum; Index++) { + // + // Firstly, find HttpUtilitiesProtocol interface + // + Status = gBS->OpenProtocol ( + HandleBuffer[Index], + &gEfiHttpUtilitiesProtocolGuid, + (VOID **) &HttpUtilitiesProtocol, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Then, uninstall HttpUtilities interface + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + HandleBuffer[Index], + &gEfiHttpUtilitiesProtocolGuid, HttpUtilitiesProtocol, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + 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 ImageHandle The firmware allocated handle for the UEFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval Others An unexpected error occurred. +**/ +EFI_STATUS +EFIAPI +HttpUtilitiesDxeDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + EFI_HANDLE Handle; + + Handle = NULL; + + // + // Install the HttpUtilities Protocol onto Handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiHttpUtilitiesProtocolGuid, + &mHttpUtilitiesProtocol, + NULL + ); + + return Status; +} + diff --git a/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.h b/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.h index 79685abb28..70e993546c 100644 --- a/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.h +++ b/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.h @@ -1,212 +1,212 @@ -/** @file - The header files of Http Utilities functions for HttpUtilities driver. - - 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 - 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. - -**/ - -#ifndef __EFI_HTTP_UTILITIES_DXE_H__ -#define __EFI_HTTP_UTILITIES_DXE_H__ - -#include - -// -// Libraries -// -#include -#include -#include -#include -#include -#include - -// -// Consumed Protocols -// -#include -#include - -// -// Protocol instances -// -extern EFI_HTTP_UTILITIES_PROTOCOL mHttpUtilitiesProtocol; - - -/** - Free existing HeaderFields. - - @param[in] HeaderFields Pointer to array of key/value header pairs waitting for free. - @param[in] FieldCount The number of header pairs in HeaderFields. - -**/ -VOID -FreeHeaderFields ( - IN EFI_HTTP_HEADER *HeaderFields, - IN UINTN FieldCount - ); - - -/** - Find required header field in HeaderFields. - - @param[in] HeaderFields Pointer to array of key/value header pairs. - @param[in] FieldCount The number of header pairs. - @param[in] FieldName Pointer to header field's name. - - @return Pointer to the queried header field. - @return NULL if not find this required header field. - -**/ -EFI_HTTP_HEADER * -FindHttpHeader ( - IN EFI_HTTP_HEADER *HeaderFields, - IN UINTN FieldCount, - IN CHAR8 *FieldName - ); - - -/** - Check whether header field called FieldName is in DeleteList. - - @param[in] DeleteList Pointer to array of key/value header pairs. - @param[in] DeleteCount The number of header pairs. - @param[in] FieldName Pointer to header field's name. - - @return TRUE if FieldName is not in DeleteList, that means this header field is valid. - @return FALSE if FieldName is in DeleteList, that means this header field is invalid. - -**/ -BOOLEAN -IsValidHttpHeader ( - IN CHAR8 *DeleteList[], - IN UINTN DeleteCount, - IN CHAR8 *FieldName - ); - - -/** - Set FieldName and FieldValue into specified HttpHeader. - - @param[in] HttpHeader Specified HttpHeader. - @param[in] FieldName FieldName of this HttpHeader. - @param[in] FieldValue FieldValue of this HttpHeader. - - - @retval EFI_SUCCESS The FieldName and FieldValue are set into HttpHeader successfully. - @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. - -**/ -EFI_STATUS -SetFieldNameAndValue ( - IN EFI_HTTP_HEADER *HttpHeader, - IN CHAR8 *FieldName, - IN CHAR8 *FieldValue - ); - - -/** - Get one key/value header pair from the raw string. - - @param[in] String Pointer to the raw string. - @param[out] FieldName Pointer to header field's name. - @param[out] FieldValue Pointer to header field's value. - - @return Pointer to the next raw string. - @return NULL if no key/value header pair from this raw string. - -**/ -CHAR8 * -GetFieldNameAndValue ( - IN CHAR8 *String, - OUT CHAR8 **FieldName, - OUT CHAR8 **FieldValue - ); - - -/** - Create HTTP header based on a combination of seed header, fields - to delete, and fields to append. - - The Build() function is used to manage the headers portion of an - HTTP message by providing the ability to add, remove, or replace - HTTP headers. - - @param[in] This Pointer to EFI_HTTP_UTILITIES_PROTOCOL instance. - @param[in] SeedMessageSize Size of the initial HTTP header. This can be zero. - @param[in] SeedMessage Initial HTTP header to be used as a base for - building a new HTTP header. If NULL, - SeedMessageSize is ignored. - @param[in] DeleteCount Number of null-terminated HTTP header field names - in DeleteList. - @param[in] DeleteList List of null-terminated HTTP header field names to - remove from SeedMessage. Only the field names are - in this list because the field values are irrelevant - to this operation. - @param[in] AppendCount Number of header fields in AppendList. - @param[in] AppendList List of HTTP headers to populate NewMessage with. - If SeedMessage is not NULL, AppendList will be - appended to the existing list from SeedMessage in - NewMessage. - @param[out] NewMessageSize Pointer to number of header fields in NewMessage. - @param[out] NewMessage Pointer to a new list of HTTP headers based on. - - @retval EFI_SUCCESS Add, remove, and replace operations succeeded. - @retval EFI_OUT_OF_RESOURCES Could not allocate memory for NewMessage. - @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: - This is NULL. -**/ -EFI_STATUS -EFIAPI -HttpUtilitiesBuild ( - IN EFI_HTTP_UTILITIES_PROTOCOL *This, - IN UINTN SeedMessageSize, - IN VOID *SeedMessage, OPTIONAL - IN UINTN DeleteCount, - IN CHAR8 *DeleteList[], OPTIONAL - IN UINTN AppendCount, - IN EFI_HTTP_HEADER *AppendList[], OPTIONAL - OUT UINTN *NewMessageSize, - OUT VOID **NewMessage - ); - - -/** - Parses HTTP header and produces an array of key/value pairs. - - The Parse() function is used to transform data stored in HttpHeader - into a list of fields paired with their corresponding values. - - @param[in] This Pointer to EFI_HTTP_UTILITIES_PROTOCOL instance. - @param[in] HttpMessage Contains raw unformatted HTTP header string. - @param[in] HttpMessageSize Size of HTTP header. - @param[out] HeaderFields Array of key/value header pairs. - @param[out] FieldCount Number of headers in HeaderFields. - - @retval EFI_SUCCESS Allocation succeeded. - @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been - initialized. - @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: - This is NULL. - HttpMessage is NULL. - HeaderFields is NULL. - FieldCount is NULL. -**/ -EFI_STATUS -EFIAPI -HttpUtilitiesParse ( - IN EFI_HTTP_UTILITIES_PROTOCOL *This, - IN CHAR8 *HttpMessage, - IN UINTN HttpMessageSize, - OUT EFI_HTTP_HEADER **HeaderFields, - OUT UINTN *FieldCount - ); - -#endif +/** @file + The header files of Http Utilities functions for HttpUtilities driver. + + 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 + 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. + +**/ + +#ifndef __EFI_HTTP_UTILITIES_DXE_H__ +#define __EFI_HTTP_UTILITIES_DXE_H__ + +#include + +// +// Libraries +// +#include +#include +#include +#include +#include +#include + +// +// Consumed Protocols +// +#include +#include + +// +// Protocol instances +// +extern EFI_HTTP_UTILITIES_PROTOCOL mHttpUtilitiesProtocol; + + +/** + Free existing HeaderFields. + + @param[in] HeaderFields Pointer to array of key/value header pairs waitting for free. + @param[in] FieldCount The number of header pairs in HeaderFields. + +**/ +VOID +FreeHeaderFields ( + IN EFI_HTTP_HEADER *HeaderFields, + IN UINTN FieldCount + ); + + +/** + Find required header field in HeaderFields. + + @param[in] HeaderFields Pointer to array of key/value header pairs. + @param[in] FieldCount The number of header pairs. + @param[in] FieldName Pointer to header field's name. + + @return Pointer to the queried header field. + @return NULL if not find this required header field. + +**/ +EFI_HTTP_HEADER * +FindHttpHeader ( + IN EFI_HTTP_HEADER *HeaderFields, + IN UINTN FieldCount, + IN CHAR8 *FieldName + ); + + +/** + Check whether header field called FieldName is in DeleteList. + + @param[in] DeleteList Pointer to array of key/value header pairs. + @param[in] DeleteCount The number of header pairs. + @param[in] FieldName Pointer to header field's name. + + @return TRUE if FieldName is not in DeleteList, that means this header field is valid. + @return FALSE if FieldName is in DeleteList, that means this header field is invalid. + +**/ +BOOLEAN +IsValidHttpHeader ( + IN CHAR8 *DeleteList[], + IN UINTN DeleteCount, + IN CHAR8 *FieldName + ); + + +/** + Set FieldName and FieldValue into specified HttpHeader. + + @param[in] HttpHeader Specified HttpHeader. + @param[in] FieldName FieldName of this HttpHeader. + @param[in] FieldValue FieldValue of this HttpHeader. + + + @retval EFI_SUCCESS The FieldName and FieldValue are set into HttpHeader successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + +**/ +EFI_STATUS +SetFieldNameAndValue ( + IN EFI_HTTP_HEADER *HttpHeader, + IN CHAR8 *FieldName, + IN CHAR8 *FieldValue + ); + + +/** + Get one key/value header pair from the raw string. + + @param[in] String Pointer to the raw string. + @param[out] FieldName Pointer to header field's name. + @param[out] FieldValue Pointer to header field's value. + + @return Pointer to the next raw string. + @return NULL if no key/value header pair from this raw string. + +**/ +CHAR8 * +GetFieldNameAndValue ( + IN CHAR8 *String, + OUT CHAR8 **FieldName, + OUT CHAR8 **FieldValue + ); + + +/** + Create HTTP header based on a combination of seed header, fields + to delete, and fields to append. + + The Build() function is used to manage the headers portion of an + HTTP message by providing the ability to add, remove, or replace + HTTP headers. + + @param[in] This Pointer to EFI_HTTP_UTILITIES_PROTOCOL instance. + @param[in] SeedMessageSize Size of the initial HTTP header. This can be zero. + @param[in] SeedMessage Initial HTTP header to be used as a base for + building a new HTTP header. If NULL, + SeedMessageSize is ignored. + @param[in] DeleteCount Number of null-terminated HTTP header field names + in DeleteList. + @param[in] DeleteList List of null-terminated HTTP header field names to + remove from SeedMessage. Only the field names are + in this list because the field values are irrelevant + to this operation. + @param[in] AppendCount Number of header fields in AppendList. + @param[in] AppendList List of HTTP headers to populate NewMessage with. + If SeedMessage is not NULL, AppendList will be + appended to the existing list from SeedMessage in + NewMessage. + @param[out] NewMessageSize Pointer to number of header fields in NewMessage. + @param[out] NewMessage Pointer to a new list of HTTP headers based on. + + @retval EFI_SUCCESS Add, remove, and replace operations succeeded. + @retval EFI_OUT_OF_RESOURCES Could not allocate memory for NewMessage. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. +**/ +EFI_STATUS +EFIAPI +HttpUtilitiesBuild ( + IN EFI_HTTP_UTILITIES_PROTOCOL *This, + IN UINTN SeedMessageSize, + IN VOID *SeedMessage, OPTIONAL + IN UINTN DeleteCount, + IN CHAR8 *DeleteList[], OPTIONAL + IN UINTN AppendCount, + IN EFI_HTTP_HEADER *AppendList[], OPTIONAL + OUT UINTN *NewMessageSize, + OUT VOID **NewMessage + ); + + +/** + Parses HTTP header and produces an array of key/value pairs. + + The Parse() function is used to transform data stored in HttpHeader + into a list of fields paired with their corresponding values. + + @param[in] This Pointer to EFI_HTTP_UTILITIES_PROTOCOL instance. + @param[in] HttpMessage Contains raw unformatted HTTP header string. + @param[in] HttpMessageSize Size of HTTP header. + @param[out] HeaderFields Array of key/value header pairs. + @param[out] FieldCount Number of headers in HeaderFields. + + @retval EFI_SUCCESS Allocation succeeded. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been + initialized. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + HttpMessage is NULL. + HeaderFields is NULL. + FieldCount is NULL. +**/ +EFI_STATUS +EFIAPI +HttpUtilitiesParse ( + IN EFI_HTTP_UTILITIES_PROTOCOL *This, + IN CHAR8 *HttpMessage, + IN UINTN HttpMessageSize, + OUT EFI_HTTP_HEADER **HeaderFields, + OUT UINTN *FieldCount + ); + +#endif diff --git a/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.inf b/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.inf index a89149a4ac..c101e6f73c 100644 --- a/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.inf +++ b/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.inf @@ -1,51 +1,51 @@ -## @file -# Implementation of EFI Http Utilities Protocol interfaces. -# -# 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 -# 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 = HttpUtilitiesDxe - FILE_GUID = 22ea234f-e72a-11e4-91f9-28d2447c4829 - MODULE_TYPE = DXE_DRIVER - VERSION_STRING = 1.0 - ENTRY_POINT = HttpUtilitiesDxeDriverEntryPoint - UNLOAD_IMAGE = HttpUtilitiesDxeUnload - -[Packages] - MdePkg/MdePkg.dec - MdeModulePkg/MdeModulePkg.dec - -[Sources] - HttpUtilitiesDxe.h - HttpUtilitiesDxe.c - HttpUtilitiesImpl.c - HttpUtilitiesProtocol.c - -[LibraryClasses] - UefiDriverEntryPoint - UefiBootServicesTableLib - MemoryAllocationLib - BaseMemoryLib - BaseLib - UefiLib - DebugLib - -[Protocols] - gEfiHttpUtilitiesProtocolGuid ## PRODUCES - -[Depex] - TRUE - -[Guids] - +## @file +# Implementation of EFI Http Utilities Protocol interfaces. +# +# 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 +# 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 = HttpUtilitiesDxe + FILE_GUID = 22ea234f-e72a-11e4-91f9-28d2447c4829 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = HttpUtilitiesDxeDriverEntryPoint + UNLOAD_IMAGE = HttpUtilitiesDxeUnload + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[Sources] + HttpUtilitiesDxe.h + HttpUtilitiesDxe.c + HttpUtilitiesImpl.c + HttpUtilitiesProtocol.c + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + BaseLib + UefiLib + DebugLib + +[Protocols] + gEfiHttpUtilitiesProtocolGuid ## PRODUCES + +[Depex] + TRUE + +[Guids] + diff --git a/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesImpl.c b/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesImpl.c index 78047c8e24..adb50af393 100644 --- a/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesImpl.c +++ b/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesImpl.c @@ -1,279 +1,279 @@ -/** @file - The functions for HttpUtilities driver. - - 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 - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php. - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "HttpUtilitiesDxe.h" - - -/** - Get the next string, which is distinguished by specified seperator. - - @param[in] String Pointer to the string. - @param[in] Seperator Specified seperator used to distinguish where is the beginning - of next string. - - @return Pointer to the next string. - @return NULL if not find or String is NULL. - -**/ -CHAR8 * -AsciiStrGetNextToken ( - IN CONST CHAR8 *String, - IN CHAR8 Seperator - ) -{ - CONST CHAR8 *Token; - - Token = String; - while (TRUE) { - if (*Token == 0) { - return NULL; - } - if (*Token == Seperator) { - return (CHAR8 *)(Token + 1); - } - Token++; - } -} - - -/** - Free existing HeaderFields. - - @param[in] HeaderFields Pointer to array of key/value header pairs waitting for free. - @param[in] FieldCount The number of header pairs in HeaderFields. - -**/ -VOID -FreeHeaderFields ( - IN EFI_HTTP_HEADER *HeaderFields, - IN UINTN FieldCount - ) -{ - UINTN Index; - - if (HeaderFields != NULL) { - for (Index = 0; Index < FieldCount; Index++) { - if (HeaderFields[Index].FieldName != NULL) { - FreePool (HeaderFields[Index].FieldName); - } - if (HeaderFields[Index].FieldValue != NULL) { - FreePool (HeaderFields[Index].FieldValue); - } - } - - FreePool (HeaderFields); - } -} - - -/** - Find required header field in HeaderFields. - - @param[in] HeaderFields Pointer to array of key/value header pairs. - @param[in] FieldCount The number of header pairs. - @param[in] FieldName Pointer to header field's name. - - @return Pointer to the queried header field. - @return NULL if not find this required header field. - -**/ -EFI_HTTP_HEADER * -FindHttpHeader ( - IN EFI_HTTP_HEADER *HeaderFields, - IN UINTN FieldCount, - IN CHAR8 *FieldName - ) -{ - UINTN Index; - - for (Index = 0; Index < FieldCount; Index++) { - if (AsciiStrCmp (FieldName, HeaderFields[Index].FieldName) == 0) { - // - // Find the required header field. - // - return &HeaderFields[Index]; - } - } - return NULL; -} - - -/** - Check whether header field called FieldName is in DeleteList. - - @param[in] DeleteList Pointer to array of key/value header pairs. - @param[in] DeleteCount The number of header pairs. - @param[in] FieldName Pointer to header field's name. - - @return TRUE if FieldName is not in DeleteList, that means this header field is valid. - @return FALSE if FieldName is in DeleteList, that means this header field is invalid. - -**/ -BOOLEAN -IsValidHttpHeader ( - IN CHAR8 *DeleteList[], - IN UINTN DeleteCount, - IN CHAR8 *FieldName - ) -{ - UINTN Index; - - for (Index = 0; Index < DeleteCount; Index++) { - if (AsciiStrCmp (FieldName, DeleteList[Index]) == 0) { - return FALSE; - } - } - - return TRUE; -} - - -/** - Set FieldName and FieldValue into specified HttpHeader. - - @param[in] HttpHeader Specified HttpHeader. - @param[in] FieldName FieldName of this HttpHeader. - @param[in] FieldValue FieldValue of this HttpHeader. - - - @retval EFI_SUCCESS The FieldName and FieldValue are set into HttpHeader successfully. - @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. - -**/ -EFI_STATUS -SetFieldNameAndValue ( - IN EFI_HTTP_HEADER *HttpHeader, - IN CHAR8 *FieldName, - IN CHAR8 *FieldValue - ) -{ - UINTN FieldNameSize; - UINTN FieldValueSize; - - if (HttpHeader->FieldName != NULL) { - FreePool (HttpHeader->FieldName); - } - if (HttpHeader->FieldValue != NULL) { - FreePool (HttpHeader->FieldValue); - } - - FieldNameSize = AsciiStrSize (FieldName); - HttpHeader->FieldName = AllocateZeroPool (FieldNameSize); - if (HttpHeader->FieldName == NULL) { - return EFI_OUT_OF_RESOURCES; - } - CopyMem (HttpHeader->FieldName, FieldName, FieldNameSize); - HttpHeader->FieldName[FieldNameSize - 1] = 0; - - FieldValueSize = AsciiStrSize (FieldValue); - HttpHeader->FieldValue = AllocateZeroPool (FieldValueSize); - if (HttpHeader->FieldValue == NULL) { - return EFI_OUT_OF_RESOURCES; - } - CopyMem (HttpHeader->FieldValue, FieldValue, FieldValueSize); - HttpHeader->FieldValue[FieldValueSize - 1] = 0; - - return EFI_SUCCESS; -} - - -/** - Get one key/value header pair from the raw string. - - @param[in] String Pointer to the raw string. - @param[out] FieldName Pointer to header field's name. - @param[out] FieldValue Pointer to header field's value. - - @return Pointer to the next raw string. - @return NULL if no key/value header pair from this raw string. - -**/ -CHAR8 * -GetFieldNameAndValue ( - IN CHAR8 *String, - OUT CHAR8 **FieldName, - OUT CHAR8 **FieldValue - ) -{ - CHAR8 *FieldNameStr; - CHAR8 *FieldValueStr; - CHAR8 *StrPtr; - - if (String == NULL || FieldName == NULL || FieldValue == NULL) { - return NULL; - } - - *FieldName = NULL; - *FieldValue = NULL; - FieldNameStr = NULL; - FieldValueStr = NULL; - StrPtr = NULL; - - // - // Each header field consists of a name followed by a colon (":") and the field value. - // - FieldNameStr = String; - FieldValueStr = AsciiStrGetNextToken (FieldNameStr, ':'); - if (FieldValueStr == NULL) { - return NULL; - } - - // - // Replace ':' with 0 - // - *(FieldValueStr - 1) = 0; - - // - // The field value MAY be preceded by any amount of LWS, though a single SP is preferred. - // - while (TRUE) { - if (*FieldValueStr == ' ' || *FieldValueStr == '\t') { - FieldValueStr ++; - } else if (*FieldValueStr == '\r' && *(FieldValueStr + 1) == '\n' && - (*(FieldValueStr + 2) == ' ' || *(FieldValueStr + 2) == '\t')) { - FieldValueStr = FieldValueStr + 3; - } else { - break; - } - } - - // - // Header fields can be extended over multiple lines by preceding each extra - // line with at least one SP or HT. - // - StrPtr = FieldValueStr; - do { - StrPtr = AsciiStrGetNextToken (StrPtr, '\r'); - if (StrPtr == NULL || *StrPtr != '\n') { - return NULL; - } - - StrPtr++; - } while (*StrPtr == ' ' || *StrPtr == '\t'); - - // - // Replace '\r' with 0 - // - *(StrPtr - 2) = 0; - - // - // Get FieldName and FieldValue. - // - *FieldName = FieldNameStr; - *FieldValue = FieldValueStr; - - return StrPtr; -} - +/** @file + The functions for HttpUtilities driver. + + 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 + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "HttpUtilitiesDxe.h" + + +/** + Get the next string, which is distinguished by specified seperator. + + @param[in] String Pointer to the string. + @param[in] Seperator Specified seperator used to distinguish where is the beginning + of next string. + + @return Pointer to the next string. + @return NULL if not find or String is NULL. + +**/ +CHAR8 * +AsciiStrGetNextToken ( + IN CONST CHAR8 *String, + IN CHAR8 Seperator + ) +{ + CONST CHAR8 *Token; + + Token = String; + while (TRUE) { + if (*Token == 0) { + return NULL; + } + if (*Token == Seperator) { + return (CHAR8 *)(Token + 1); + } + Token++; + } +} + + +/** + Free existing HeaderFields. + + @param[in] HeaderFields Pointer to array of key/value header pairs waitting for free. + @param[in] FieldCount The number of header pairs in HeaderFields. + +**/ +VOID +FreeHeaderFields ( + IN EFI_HTTP_HEADER *HeaderFields, + IN UINTN FieldCount + ) +{ + UINTN Index; + + if (HeaderFields != NULL) { + for (Index = 0; Index < FieldCount; Index++) { + if (HeaderFields[Index].FieldName != NULL) { + FreePool (HeaderFields[Index].FieldName); + } + if (HeaderFields[Index].FieldValue != NULL) { + FreePool (HeaderFields[Index].FieldValue); + } + } + + FreePool (HeaderFields); + } +} + + +/** + Find required header field in HeaderFields. + + @param[in] HeaderFields Pointer to array of key/value header pairs. + @param[in] FieldCount The number of header pairs. + @param[in] FieldName Pointer to header field's name. + + @return Pointer to the queried header field. + @return NULL if not find this required header field. + +**/ +EFI_HTTP_HEADER * +FindHttpHeader ( + IN EFI_HTTP_HEADER *HeaderFields, + IN UINTN FieldCount, + IN CHAR8 *FieldName + ) +{ + UINTN Index; + + for (Index = 0; Index < FieldCount; Index++) { + if (AsciiStrCmp (FieldName, HeaderFields[Index].FieldName) == 0) { + // + // Find the required header field. + // + return &HeaderFields[Index]; + } + } + return NULL; +} + + +/** + Check whether header field called FieldName is in DeleteList. + + @param[in] DeleteList Pointer to array of key/value header pairs. + @param[in] DeleteCount The number of header pairs. + @param[in] FieldName Pointer to header field's name. + + @return TRUE if FieldName is not in DeleteList, that means this header field is valid. + @return FALSE if FieldName is in DeleteList, that means this header field is invalid. + +**/ +BOOLEAN +IsValidHttpHeader ( + IN CHAR8 *DeleteList[], + IN UINTN DeleteCount, + IN CHAR8 *FieldName + ) +{ + UINTN Index; + + for (Index = 0; Index < DeleteCount; Index++) { + if (AsciiStrCmp (FieldName, DeleteList[Index]) == 0) { + return FALSE; + } + } + + return TRUE; +} + + +/** + Set FieldName and FieldValue into specified HttpHeader. + + @param[in] HttpHeader Specified HttpHeader. + @param[in] FieldName FieldName of this HttpHeader. + @param[in] FieldValue FieldValue of this HttpHeader. + + + @retval EFI_SUCCESS The FieldName and FieldValue are set into HttpHeader successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + +**/ +EFI_STATUS +SetFieldNameAndValue ( + IN EFI_HTTP_HEADER *HttpHeader, + IN CHAR8 *FieldName, + IN CHAR8 *FieldValue + ) +{ + UINTN FieldNameSize; + UINTN FieldValueSize; + + if (HttpHeader->FieldName != NULL) { + FreePool (HttpHeader->FieldName); + } + if (HttpHeader->FieldValue != NULL) { + FreePool (HttpHeader->FieldValue); + } + + FieldNameSize = AsciiStrSize (FieldName); + HttpHeader->FieldName = AllocateZeroPool (FieldNameSize); + if (HttpHeader->FieldName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (HttpHeader->FieldName, FieldName, FieldNameSize); + HttpHeader->FieldName[FieldNameSize - 1] = 0; + + FieldValueSize = AsciiStrSize (FieldValue); + HttpHeader->FieldValue = AllocateZeroPool (FieldValueSize); + if (HttpHeader->FieldValue == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (HttpHeader->FieldValue, FieldValue, FieldValueSize); + HttpHeader->FieldValue[FieldValueSize - 1] = 0; + + return EFI_SUCCESS; +} + + +/** + Get one key/value header pair from the raw string. + + @param[in] String Pointer to the raw string. + @param[out] FieldName Pointer to header field's name. + @param[out] FieldValue Pointer to header field's value. + + @return Pointer to the next raw string. + @return NULL if no key/value header pair from this raw string. + +**/ +CHAR8 * +GetFieldNameAndValue ( + IN CHAR8 *String, + OUT CHAR8 **FieldName, + OUT CHAR8 **FieldValue + ) +{ + CHAR8 *FieldNameStr; + CHAR8 *FieldValueStr; + CHAR8 *StrPtr; + + if (String == NULL || FieldName == NULL || FieldValue == NULL) { + return NULL; + } + + *FieldName = NULL; + *FieldValue = NULL; + FieldNameStr = NULL; + FieldValueStr = NULL; + StrPtr = NULL; + + // + // Each header field consists of a name followed by a colon (":") and the field value. + // + FieldNameStr = String; + FieldValueStr = AsciiStrGetNextToken (FieldNameStr, ':'); + if (FieldValueStr == NULL) { + return NULL; + } + + // + // Replace ':' with 0 + // + *(FieldValueStr - 1) = 0; + + // + // The field value MAY be preceded by any amount of LWS, though a single SP is preferred. + // + while (TRUE) { + if (*FieldValueStr == ' ' || *FieldValueStr == '\t') { + FieldValueStr ++; + } else if (*FieldValueStr == '\r' && *(FieldValueStr + 1) == '\n' && + (*(FieldValueStr + 2) == ' ' || *(FieldValueStr + 2) == '\t')) { + FieldValueStr = FieldValueStr + 3; + } else { + break; + } + } + + // + // Header fields can be extended over multiple lines by preceding each extra + // line with at least one SP or HT. + // + StrPtr = FieldValueStr; + do { + StrPtr = AsciiStrGetNextToken (StrPtr, '\r'); + if (StrPtr == NULL || *StrPtr != '\n') { + return NULL; + } + + StrPtr++; + } while (*StrPtr == ' ' || *StrPtr == '\t'); + + // + // Replace '\r' with 0 + // + *(StrPtr - 2) = 0; + + // + // Get FieldName and FieldValue. + // + *FieldName = FieldNameStr; + *FieldValue = FieldValueStr; + + return StrPtr; +} + diff --git a/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesProtocol.c b/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesProtocol.c index 71b39f2831..8c29f20adf 100644 --- a/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesProtocol.c +++ b/NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesProtocol.c @@ -1,393 +1,393 @@ -/** @file - Implementation of EFI_HTTP_PROTOCOL protocol interfaces. - - 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 - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "HttpUtilitiesDxe.h" - -EFI_HTTP_UTILITIES_PROTOCOL mHttpUtilitiesProtocol = { - HttpUtilitiesBuild, - HttpUtilitiesParse -}; - - -/** - Create HTTP header based on a combination of seed header, fields - to delete, and fields to append. - - The Build() function is used to manage the headers portion of an - HTTP message by providing the ability to add, remove, or replace - HTTP headers. - - @param[in] This Pointer to EFI_HTTP_UTILITIES_PROTOCOL instance. - @param[in] SeedMessageSize Size of the initial HTTP header. This can be zero. - @param[in] SeedMessage Initial HTTP header to be used as a base for - building a new HTTP header. If NULL, - SeedMessageSize is ignored. - @param[in] DeleteCount Number of null-terminated HTTP header field names - in DeleteList. - @param[in] DeleteList List of null-terminated HTTP header field names to - remove from SeedMessage. Only the field names are - in this list because the field values are irrelevant - to this operation. - @param[in] AppendCount Number of header fields in AppendList. - @param[in] AppendList List of HTTP headers to populate NewMessage with. - If SeedMessage is not NULL, AppendList will be - appended to the existing list from SeedMessage in - NewMessage. - @param[out] NewMessageSize Pointer to number of header fields in NewMessage. - @param[out] NewMessage Pointer to a new list of HTTP headers based on. - - @retval EFI_SUCCESS Add, remove, and replace operations succeeded. - @retval EFI_OUT_OF_RESOURCES Could not allocate memory for NewMessage. - @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: - This is NULL. -**/ -EFI_STATUS -EFIAPI -HttpUtilitiesBuild ( - IN EFI_HTTP_UTILITIES_PROTOCOL *This, - IN UINTN SeedMessageSize, - IN VOID *SeedMessage, OPTIONAL - IN UINTN DeleteCount, - IN CHAR8 *DeleteList[], OPTIONAL - IN UINTN AppendCount, - IN EFI_HTTP_HEADER *AppendList[], OPTIONAL - OUT UINTN *NewMessageSize, - OUT VOID **NewMessage - ) -{ - EFI_STATUS Status; - EFI_HTTP_HEADER *SeedHeaderFields; - UINTN SeedFieldCount; - UINTN Index; - EFI_HTTP_HEADER *TempHeaderFields; - UINTN TempFieldCount; - EFI_HTTP_HEADER *NewHeaderFields; - UINTN NewFieldCount; - EFI_HTTP_HEADER *HttpHeader; - UINTN StrLength; - UINT8 *NewMessagePtr; - - SeedHeaderFields = NULL; - SeedFieldCount = 0; - TempHeaderFields = NULL; - TempFieldCount = 0; - NewHeaderFields = NULL; - NewFieldCount = 0; - - HttpHeader = NULL; - StrLength = 0; - NewMessagePtr = NULL; - *NewMessageSize = 0; - Status = EFI_SUCCESS; - - if (This == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (SeedMessage != NULL) { - Status = This->Parse ( - This, - SeedMessage, - SeedMessageSize, - &SeedHeaderFields, - &SeedFieldCount - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - } - - // - // Handle DeleteList - // - if (SeedFieldCount != 0 && DeleteCount != 0) { - TempHeaderFields = AllocateZeroPool (SeedFieldCount * sizeof(EFI_HTTP_HEADER)); - if (TempHeaderFields == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - - for (Index = 0, TempFieldCount = 0; Index < SeedFieldCount; Index++) { - // - // Check whether each SeedHeaderFields member is in DeleteList - // - if (IsValidHttpHeader( DeleteList, DeleteCount, SeedHeaderFields[Index].FieldName)) { - Status = SetFieldNameAndValue ( - &TempHeaderFields[TempFieldCount], - SeedHeaderFields[Index].FieldName, - SeedHeaderFields[Index].FieldValue - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - TempFieldCount++; - } - } - } else { - TempHeaderFields = SeedHeaderFields; - TempFieldCount = SeedFieldCount; - } - - // - // Handle AppendList - // - NewHeaderFields = AllocateZeroPool ((TempFieldCount + AppendCount) * sizeof (EFI_HTTP_HEADER)); - if (NewHeaderFields == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - - for (Index = 0; Index < TempFieldCount; Index++) { - Status = SetFieldNameAndValue ( - &NewHeaderFields[Index], - TempHeaderFields[Index].FieldName, - TempHeaderFields[Index].FieldValue - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - } - - NewFieldCount = TempFieldCount; - - for (Index = 0; Index < AppendCount; Index++) { - HttpHeader = FindHttpHeader (NewHeaderFields, NewFieldCount, AppendList[Index]->FieldName); - if (HttpHeader != NULL) { - Status = SetFieldNameAndValue ( - HttpHeader, - AppendList[Index]->FieldName, - AppendList[Index]->FieldValue - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - } else { - Status = SetFieldNameAndValue ( - &NewHeaderFields[NewFieldCount], - AppendList[Index]->FieldName, - AppendList[Index]->FieldValue - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - NewFieldCount++; - } - } - - // - // Calculate NewMessageSize, then build NewMessage - // - for (Index = 0; Index < NewFieldCount; Index++) { - HttpHeader = &NewHeaderFields[Index]; - - StrLength = AsciiStrLen (HttpHeader->FieldName); - *NewMessageSize += StrLength; - - StrLength = sizeof(": ") - 1; - *NewMessageSize += StrLength; - - StrLength = AsciiStrLen (HttpHeader->FieldValue); - *NewMessageSize += StrLength; - - StrLength = sizeof("\r\n") - 1; - *NewMessageSize += StrLength; - } - StrLength = sizeof("\r\n") - 1; - *NewMessageSize += StrLength; - - // - // Final 0 for end flag - // - *NewMessageSize += 1; - - *NewMessage = AllocateZeroPool (*NewMessageSize); - if (*NewMessage == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - - NewMessagePtr = (UINT8 *)(*NewMessage); - - for (Index = 0; Index < NewFieldCount; Index++) { - HttpHeader = &NewHeaderFields[Index]; - - StrLength = AsciiStrLen (HttpHeader->FieldName); - CopyMem (NewMessagePtr, HttpHeader->FieldName, StrLength); - NewMessagePtr += StrLength; - - StrLength = sizeof(": ") - 1; - CopyMem (NewMessagePtr, ": ", StrLength); - NewMessagePtr += StrLength; - - StrLength = AsciiStrLen (HttpHeader->FieldValue); - CopyMem (NewMessagePtr, HttpHeader->FieldValue, StrLength); - NewMessagePtr += StrLength; - - StrLength = sizeof("\r\n") - 1; - CopyMem (NewMessagePtr, "\r\n", StrLength); - NewMessagePtr += StrLength; - } - StrLength = sizeof("\r\n") - 1; - CopyMem (NewMessagePtr, "\r\n", StrLength); - NewMessagePtr += StrLength; - - *NewMessagePtr = 0; - - ASSERT (*NewMessageSize == (UINTN)NewMessagePtr - (UINTN)(*NewMessage) + 1); - - // - // Free allocated buffer - // -ON_EXIT: - if (SeedHeaderFields != NULL) { - FreeHeaderFields(SeedHeaderFields, SeedFieldCount); - } - - if (TempHeaderFields != NULL) { - FreeHeaderFields(TempHeaderFields, TempFieldCount); - } - - if (NewHeaderFields != NULL) { - FreeHeaderFields(NewHeaderFields, NewFieldCount); - } - - return Status; -} - - -/** - Parses HTTP header and produces an array of key/value pairs. - - The Parse() function is used to transform data stored in HttpHeader - into a list of fields paired with their corresponding values. - - @param[in] This Pointer to EFI_HTTP_UTILITIES_PROTOCOL instance. - @param[in] HttpMessage Contains raw unformatted HTTP header string. - @param[in] HttpMessageSize Size of HTTP header. - @param[out] HeaderFields Array of key/value header pairs. - @param[out] FieldCount Number of headers in HeaderFields. - - @retval EFI_SUCCESS Allocation succeeded. - @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been - initialized. - @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: - This is NULL. - HttpMessage is NULL. - HeaderFields is NULL. - FieldCount is NULL. -**/ -EFI_STATUS -EFIAPI -HttpUtilitiesParse ( - IN EFI_HTTP_UTILITIES_PROTOCOL *This, - IN CHAR8 *HttpMessage, - IN UINTN HttpMessageSize, - OUT EFI_HTTP_HEADER **HeaderFields, - OUT UINTN *FieldCount - ) -{ - EFI_STATUS Status; - CHAR8 *TempHttpMessage; - CHAR8 *Token; - CHAR8 *NextToken; - CHAR8 *FieldName; - CHAR8 *FieldValue; - UINTN Index; - - Status = EFI_SUCCESS; - TempHttpMessage = NULL; - *FieldCount = 0; - Token = NULL; - NextToken = NULL; - FieldName = NULL; - FieldValue = NULL; - Index = 0; - - if (This == NULL || HttpMessage == NULL || HeaderFields == NULL || FieldCount == NULL) { - return EFI_INVALID_PARAMETER; - } - - TempHttpMessage = AllocateZeroPool (HttpMessageSize); - if (TempHttpMessage == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - CopyMem (TempHttpMessage, HttpMessage, HttpMessageSize); - - // - // Get header number - // - Token = TempHttpMessage; - while (TRUE) { - FieldName = NULL; - FieldValue = NULL; - NextToken = GetFieldNameAndValue (Token, &FieldName, &FieldValue); - Token = NextToken; - if (FieldName == NULL || FieldValue == NULL) { - break; - } - - (*FieldCount)++; - } - - if (*FieldCount == 0) { - Status = EFI_INVALID_PARAMETER; - goto ON_EXIT; - } - - // - // Allocate buffer for header - // - *HeaderFields = AllocateZeroPool ((*FieldCount) * sizeof(EFI_HTTP_HEADER)); - if (*HeaderFields == NULL) { - *FieldCount = 0; - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - - CopyMem (TempHttpMessage, HttpMessage, HttpMessageSize); - - // - // Set Field and Value to each header - // - Token = TempHttpMessage; - while (Index < *FieldCount) { - FieldName = NULL; - FieldValue = NULL; - NextToken = GetFieldNameAndValue (Token, &FieldName, &FieldValue); - Token = NextToken; - if (FieldName == NULL || FieldValue == NULL) { - break; - } - - Status = SetFieldNameAndValue (&(*HeaderFields)[Index], FieldName, FieldValue); - if (EFI_ERROR (Status)) { - *FieldCount = 0; - FreeHeaderFields (*HeaderFields, Index); - goto ON_EXIT; - } - - Index++; - } - - // - // Free allocated buffer - // -ON_EXIT: - if (TempHttpMessage != NULL) { - FreePool (TempHttpMessage); - } - - return Status; +/** @file + Implementation of EFI_HTTP_PROTOCOL protocol interfaces. + + 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 + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "HttpUtilitiesDxe.h" + +EFI_HTTP_UTILITIES_PROTOCOL mHttpUtilitiesProtocol = { + HttpUtilitiesBuild, + HttpUtilitiesParse +}; + + +/** + Create HTTP header based on a combination of seed header, fields + to delete, and fields to append. + + The Build() function is used to manage the headers portion of an + HTTP message by providing the ability to add, remove, or replace + HTTP headers. + + @param[in] This Pointer to EFI_HTTP_UTILITIES_PROTOCOL instance. + @param[in] SeedMessageSize Size of the initial HTTP header. This can be zero. + @param[in] SeedMessage Initial HTTP header to be used as a base for + building a new HTTP header. If NULL, + SeedMessageSize is ignored. + @param[in] DeleteCount Number of null-terminated HTTP header field names + in DeleteList. + @param[in] DeleteList List of null-terminated HTTP header field names to + remove from SeedMessage. Only the field names are + in this list because the field values are irrelevant + to this operation. + @param[in] AppendCount Number of header fields in AppendList. + @param[in] AppendList List of HTTP headers to populate NewMessage with. + If SeedMessage is not NULL, AppendList will be + appended to the existing list from SeedMessage in + NewMessage. + @param[out] NewMessageSize Pointer to number of header fields in NewMessage. + @param[out] NewMessage Pointer to a new list of HTTP headers based on. + + @retval EFI_SUCCESS Add, remove, and replace operations succeeded. + @retval EFI_OUT_OF_RESOURCES Could not allocate memory for NewMessage. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. +**/ +EFI_STATUS +EFIAPI +HttpUtilitiesBuild ( + IN EFI_HTTP_UTILITIES_PROTOCOL *This, + IN UINTN SeedMessageSize, + IN VOID *SeedMessage, OPTIONAL + IN UINTN DeleteCount, + IN CHAR8 *DeleteList[], OPTIONAL + IN UINTN AppendCount, + IN EFI_HTTP_HEADER *AppendList[], OPTIONAL + OUT UINTN *NewMessageSize, + OUT VOID **NewMessage + ) +{ + EFI_STATUS Status; + EFI_HTTP_HEADER *SeedHeaderFields; + UINTN SeedFieldCount; + UINTN Index; + EFI_HTTP_HEADER *TempHeaderFields; + UINTN TempFieldCount; + EFI_HTTP_HEADER *NewHeaderFields; + UINTN NewFieldCount; + EFI_HTTP_HEADER *HttpHeader; + UINTN StrLength; + UINT8 *NewMessagePtr; + + SeedHeaderFields = NULL; + SeedFieldCount = 0; + TempHeaderFields = NULL; + TempFieldCount = 0; + NewHeaderFields = NULL; + NewFieldCount = 0; + + HttpHeader = NULL; + StrLength = 0; + NewMessagePtr = NULL; + *NewMessageSize = 0; + Status = EFI_SUCCESS; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (SeedMessage != NULL) { + Status = This->Parse ( + This, + SeedMessage, + SeedMessageSize, + &SeedHeaderFields, + &SeedFieldCount + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } + + // + // Handle DeleteList + // + if (SeedFieldCount != 0 && DeleteCount != 0) { + TempHeaderFields = AllocateZeroPool (SeedFieldCount * sizeof(EFI_HTTP_HEADER)); + if (TempHeaderFields == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + for (Index = 0, TempFieldCount = 0; Index < SeedFieldCount; Index++) { + // + // Check whether each SeedHeaderFields member is in DeleteList + // + if (IsValidHttpHeader( DeleteList, DeleteCount, SeedHeaderFields[Index].FieldName)) { + Status = SetFieldNameAndValue ( + &TempHeaderFields[TempFieldCount], + SeedHeaderFields[Index].FieldName, + SeedHeaderFields[Index].FieldValue + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + TempFieldCount++; + } + } + } else { + TempHeaderFields = SeedHeaderFields; + TempFieldCount = SeedFieldCount; + } + + // + // Handle AppendList + // + NewHeaderFields = AllocateZeroPool ((TempFieldCount + AppendCount) * sizeof (EFI_HTTP_HEADER)); + if (NewHeaderFields == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + for (Index = 0; Index < TempFieldCount; Index++) { + Status = SetFieldNameAndValue ( + &NewHeaderFields[Index], + TempHeaderFields[Index].FieldName, + TempHeaderFields[Index].FieldValue + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } + + NewFieldCount = TempFieldCount; + + for (Index = 0; Index < AppendCount; Index++) { + HttpHeader = FindHttpHeader (NewHeaderFields, NewFieldCount, AppendList[Index]->FieldName); + if (HttpHeader != NULL) { + Status = SetFieldNameAndValue ( + HttpHeader, + AppendList[Index]->FieldName, + AppendList[Index]->FieldValue + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } else { + Status = SetFieldNameAndValue ( + &NewHeaderFields[NewFieldCount], + AppendList[Index]->FieldName, + AppendList[Index]->FieldValue + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + NewFieldCount++; + } + } + + // + // Calculate NewMessageSize, then build NewMessage + // + for (Index = 0; Index < NewFieldCount; Index++) { + HttpHeader = &NewHeaderFields[Index]; + + StrLength = AsciiStrLen (HttpHeader->FieldName); + *NewMessageSize += StrLength; + + StrLength = sizeof(": ") - 1; + *NewMessageSize += StrLength; + + StrLength = AsciiStrLen (HttpHeader->FieldValue); + *NewMessageSize += StrLength; + + StrLength = sizeof("\r\n") - 1; + *NewMessageSize += StrLength; + } + StrLength = sizeof("\r\n") - 1; + *NewMessageSize += StrLength; + + // + // Final 0 for end flag + // + *NewMessageSize += 1; + + *NewMessage = AllocateZeroPool (*NewMessageSize); + if (*NewMessage == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + NewMessagePtr = (UINT8 *)(*NewMessage); + + for (Index = 0; Index < NewFieldCount; Index++) { + HttpHeader = &NewHeaderFields[Index]; + + StrLength = AsciiStrLen (HttpHeader->FieldName); + CopyMem (NewMessagePtr, HttpHeader->FieldName, StrLength); + NewMessagePtr += StrLength; + + StrLength = sizeof(": ") - 1; + CopyMem (NewMessagePtr, ": ", StrLength); + NewMessagePtr += StrLength; + + StrLength = AsciiStrLen (HttpHeader->FieldValue); + CopyMem (NewMessagePtr, HttpHeader->FieldValue, StrLength); + NewMessagePtr += StrLength; + + StrLength = sizeof("\r\n") - 1; + CopyMem (NewMessagePtr, "\r\n", StrLength); + NewMessagePtr += StrLength; + } + StrLength = sizeof("\r\n") - 1; + CopyMem (NewMessagePtr, "\r\n", StrLength); + NewMessagePtr += StrLength; + + *NewMessagePtr = 0; + + ASSERT (*NewMessageSize == (UINTN)NewMessagePtr - (UINTN)(*NewMessage) + 1); + + // + // Free allocated buffer + // +ON_EXIT: + if (SeedHeaderFields != NULL) { + FreeHeaderFields(SeedHeaderFields, SeedFieldCount); + } + + if (TempHeaderFields != NULL) { + FreeHeaderFields(TempHeaderFields, TempFieldCount); + } + + if (NewHeaderFields != NULL) { + FreeHeaderFields(NewHeaderFields, NewFieldCount); + } + + return Status; +} + + +/** + Parses HTTP header and produces an array of key/value pairs. + + The Parse() function is used to transform data stored in HttpHeader + into a list of fields paired with their corresponding values. + + @param[in] This Pointer to EFI_HTTP_UTILITIES_PROTOCOL instance. + @param[in] HttpMessage Contains raw unformatted HTTP header string. + @param[in] HttpMessageSize Size of HTTP header. + @param[out] HeaderFields Array of key/value header pairs. + @param[out] FieldCount Number of headers in HeaderFields. + + @retval EFI_SUCCESS Allocation succeeded. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been + initialized. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + HttpMessage is NULL. + HeaderFields is NULL. + FieldCount is NULL. +**/ +EFI_STATUS +EFIAPI +HttpUtilitiesParse ( + IN EFI_HTTP_UTILITIES_PROTOCOL *This, + IN CHAR8 *HttpMessage, + IN UINTN HttpMessageSize, + OUT EFI_HTTP_HEADER **HeaderFields, + OUT UINTN *FieldCount + ) +{ + EFI_STATUS Status; + CHAR8 *TempHttpMessage; + CHAR8 *Token; + CHAR8 *NextToken; + CHAR8 *FieldName; + CHAR8 *FieldValue; + UINTN Index; + + Status = EFI_SUCCESS; + TempHttpMessage = NULL; + *FieldCount = 0; + Token = NULL; + NextToken = NULL; + FieldName = NULL; + FieldValue = NULL; + Index = 0; + + if (This == NULL || HttpMessage == NULL || HeaderFields == NULL || FieldCount == NULL) { + return EFI_INVALID_PARAMETER; + } + + TempHttpMessage = AllocateZeroPool (HttpMessageSize); + if (TempHttpMessage == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (TempHttpMessage, HttpMessage, HttpMessageSize); + + // + // Get header number + // + Token = TempHttpMessage; + while (TRUE) { + FieldName = NULL; + FieldValue = NULL; + NextToken = GetFieldNameAndValue (Token, &FieldName, &FieldValue); + Token = NextToken; + if (FieldName == NULL || FieldValue == NULL) { + break; + } + + (*FieldCount)++; + } + + if (*FieldCount == 0) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + // + // Allocate buffer for header + // + *HeaderFields = AllocateZeroPool ((*FieldCount) * sizeof(EFI_HTTP_HEADER)); + if (*HeaderFields == NULL) { + *FieldCount = 0; + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + CopyMem (TempHttpMessage, HttpMessage, HttpMessageSize); + + // + // Set Field and Value to each header + // + Token = TempHttpMessage; + while (Index < *FieldCount) { + FieldName = NULL; + FieldValue = NULL; + NextToken = GetFieldNameAndValue (Token, &FieldName, &FieldValue); + Token = NextToken; + if (FieldName == NULL || FieldValue == NULL) { + break; + } + + Status = SetFieldNameAndValue (&(*HeaderFields)[Index], FieldName, FieldValue); + if (EFI_ERROR (Status)) { + *FieldCount = 0; + FreeHeaderFields (*HeaderFields, Index); + goto ON_EXIT; + } + + Index++; + } + + // + // Free allocated buffer + // +ON_EXIT: + if (TempHttpMessage != NULL) { + FreePool (TempHttpMessage); + } + + return Status; } \ No newline at end of file -- 2.39.2