summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/NetworkPkg/HttpBootDxe/HttpBootConfig.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/NetworkPkg/HttpBootDxe/HttpBootConfig.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/NetworkPkg/HttpBootDxe/HttpBootConfig.c700
1 files changed, 700 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/NetworkPkg/HttpBootDxe/HttpBootConfig.c b/src/VBox/Devices/EFI/Firmware/NetworkPkg/HttpBootDxe/HttpBootConfig.c
new file mode 100644
index 00000000..3814d196
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/NetworkPkg/HttpBootDxe/HttpBootConfig.c
@@ -0,0 +1,700 @@
+/** @file
+ Helper functions for configuring or getting the parameters relating to HTTP Boot.
+
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "HttpBootDxe.h"
+#include <Library/UefiBootManagerLib.h>
+
+CHAR16 mHttpBootConfigStorageName[] = L"HTTP_BOOT_CONFIG_IFR_NVDATA";
+
+/**
+ Add new boot option for HTTP boot.
+
+ @param[in] Private Pointer to the driver private data.
+ @param[in] UsingIpv6 Set to TRUE if creating boot option for IPv6.
+ @param[in] Description The description text of the boot option.
+ @param[in] Uri The URI string of the boot file.
+
+ @retval EFI_SUCCESS The boot option is created successfully.
+ @retval Others Failed to create new boot option.
+
+**/
+EFI_STATUS
+HttpBootAddBootOption (
+ IN HTTP_BOOT_PRIVATE_DATA *Private,
+ IN BOOLEAN UsingIpv6,
+ IN CHAR16 *Description,
+ IN CHAR16 *Uri
+ )
+{
+ EFI_DEV_PATH *Node;
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ UINTN Length;
+ CHAR8 AsciiUri[URI_STR_MAX_SIZE];
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
+
+ NewDevicePath = NULL;
+ Node = NULL;
+ TmpDevicePath = NULL;
+
+ if (StrLen (Description) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Convert the scheme to all lower case.
+ //
+ for (Index = 0; Index < StrLen (Uri); Index++) {
+ if (Uri[Index] == L':') {
+ break;
+ }
+ if (Uri[Index] >= L'A' && Uri[Index] <= L'Z') {
+ Uri[Index] -= (CHAR16)(L'A' - L'a');
+ }
+ }
+
+ //
+ // Only accept empty URI, or http and https URI.
+ //
+ if ((StrLen (Uri) != 0) && (StrnCmp (Uri, L"http://", 7) != 0) && (StrnCmp (Uri, L"https://", 8) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Create a new device path by appending the IP node and URI node to
+ // the driver's parent device path
+ //
+ if (!UsingIpv6) {
+ Node = AllocateZeroPool (sizeof (IPv4_DEVICE_PATH));
+ if (Node == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+ Node->Ipv4.Header.Type = MESSAGING_DEVICE_PATH;
+ Node->Ipv4.Header.SubType = MSG_IPv4_DP;
+ SetDevicePathNodeLength (Node, sizeof (IPv4_DEVICE_PATH));
+ } else {
+ Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH));
+ if (Node == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+ Node->Ipv6.Header.Type = MESSAGING_DEVICE_PATH;
+ Node->Ipv6.Header.SubType = MSG_IPv6_DP;
+ SetDevicePathNodeLength (Node, sizeof (IPv6_DEVICE_PATH));
+ }
+ TmpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
+ FreePool (Node);
+ if (TmpDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Update the URI node with the input boot file URI.
+ //
+ UnicodeStrToAsciiStrS (Uri, AsciiUri, sizeof (AsciiUri));
+ Length = sizeof (EFI_DEVICE_PATH_PROTOCOL) + AsciiStrSize (AsciiUri);
+ Node = AllocatePool (Length);
+ if (Node == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ FreePool (TmpDevicePath);
+ goto ON_EXIT;
+ }
+ Node->DevPath.Type = MESSAGING_DEVICE_PATH;
+ Node->DevPath.SubType = MSG_URI_DP;
+ SetDevicePathNodeLength (Node, Length);
+ CopyMem ((UINT8*) Node + sizeof (EFI_DEVICE_PATH_PROTOCOL), AsciiUri, AsciiStrSize (AsciiUri));
+ NewDevicePath = AppendDevicePathNode (TmpDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
+ FreePool (Node);
+ FreePool (TmpDevicePath);
+ if (NewDevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Add a new load option.
+ //
+ Status = EfiBootManagerInitializeLoadOption (
+ &NewOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ Description,
+ NewDevicePath,
+ NULL,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1);
+ EfiBootManagerFreeLoadOption (&NewOption);
+
+ON_EXIT:
+
+ if (NewDevicePath != NULL) {
+ FreePool (NewDevicePath);
+ }
+
+ return Status;
+}
+
+/**
+
+ This function allows the caller to request the current
+ configuration for one or more named elements. The resulting
+ string is in <ConfigAltResp> format. Also, any and all alternative
+ configuration strings shall be appended to the end of the
+ current configuration string. If they are, they must appear
+ after the current configuration. They must contain the same
+ routing (GUID, NAME, PATH) as the current configuration string.
+ They must have an additional description indicating the type of
+ alternative configuration the string represents,
+ "ALTCFG=<StringToken>". That <StringToken> (when
+ converted from Hex UNICODE to binary) is a reference to a
+ string in the associated string pack.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+
+ @param[in] Request A null-terminated Unicode string in
+ <ConfigRequest> format. Note that this
+ includes the routing information as well as
+ the configurable name / value pairs. It is
+ invalid for this string to be in
+ <MultiConfigRequest> format.
+
+ @param[out] Progress On return, points to a character in the
+ Request string. Points to the string's null
+ terminator if request was successful. Points
+ to the most recent "&" before the first
+ failing name / value pair (or the beginning
+ of the string if the failure is in the first
+ name / value pair) if the request was not successful.
+
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values
+ filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results string is filled with the
+ values corresponding to all requested
+ names.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
+ parts of the results that must be
+ stored awaiting possible future
+ protocols.
+
+ @retval EFI_INVALID_PARAMETER For example, passing in a NULL
+ for the Request parameter
+ would result in this type of
+ error. In this case, the
+ Progress parameter would be
+ set to NULL.
+
+ @retval EFI_NOT_FOUND Routing data doesn't match any
+ known driver. Progress set to the
+ first character in the routing header.
+ Note: There is no requirement that the
+ driver validate the routing data. It
+ must skip the <ConfigHdr> in order to
+ process the names.
+
+ @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set
+ to most recent "&" before the
+ error or the beginning of the
+ string.
+
+ @retval EFI_INVALID_PARAMETER Unknown name. Progress points
+ to the & before the name in
+ question.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpBootFormExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;
+ EFI_STRING ConfigRequestHdr;
+ EFI_STRING ConfigRequest;
+ BOOLEAN AllocatedRequest;
+ UINTN Size;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Request;
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gHttpBootConfigGuid, mHttpBootConfigStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ AllocatedRequest = FALSE;
+ Size = 0;
+
+ CallbackInfo = HTTP_BOOT_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ BufferSize = sizeof (HTTP_BOOT_CONFIG_IFR_NVDATA);
+ ZeroMem (&CallbackInfo->HttpBootNvData, BufferSize);
+ StrCpyS (CallbackInfo->HttpBootNvData.Description, DESCRIPTION_STR_MAX_SIZE / sizeof (CHAR16), HTTP_BOOT_DEFAULT_DESCRIPTION_STR);
+
+ ConfigRequest = Request;
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
+ //
+ // Request has no request element, construct full request string.
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&gHttpBootConfigGuid, mHttpBootConfigStorageName, CallbackInfo->ChildHandle);
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ if (ConfigRequest == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
+ FreePool (ConfigRequestHdr);
+ }
+
+ Status = gHiiConfigRouting->BlockToConfig (
+ gHiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *) &CallbackInfo->HttpBootNvData,
+ BufferSize,
+ Results,
+ Progress
+ );
+
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ ConfigRequest = NULL;
+ }
+ //
+ // Set Progress string to the original request string.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+
+ This function applies changes in a driver's configuration.
+ Input is a Configuration, which has the routing data for this
+ driver followed by name / value configuration pairs. The driver
+ must apply those pairs to its configurable storage. If the
+ driver's configuration is stored in a linear block of data
+ and the driver's name / value pairs are in <BlockConfig>
+ format, it may use the ConfigToBlock helper function (above) to
+ simplify the job.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+
+ @param[in] Configuration A null-terminated Unicode string in
+ <ConfigString> format.
+
+ @param[out] Progress A pointer to a string filled in with the
+ offset of the most recent '&' before the
+ first failing name / value pair (or the
+ beginning of the string if the failure
+ is in the first name / value pair) or
+ the terminating NULL if all was
+ successful.
+
+ @retval EFI_SUCCESS The results have been distributed or are
+ awaiting distribution.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
+ parts of the results that must be
+ stored awaiting possible future
+ protocols.
+
+ @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
+ Results parameter would result
+ in this type of error.
+
+ @retval EFI_NOT_FOUND Target for the specified routing data
+ was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpBootFormRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;
+ HTTP_BOOT_PRIVATE_DATA *Private;
+
+ if (Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Progress = Configuration;
+
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: there is no name for Name/Value storage, only GUID will be checked
+ //
+ if (!HiiIsConfigHdrMatch (Configuration, &gHttpBootConfigGuid, mHttpBootConfigStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ CallbackInfo = HTTP_BOOT_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);
+ Private = HTTP_BOOT_PRIVATE_DATA_FROM_CALLBACK_INFO (CallbackInfo);
+
+ BufferSize = sizeof (HTTP_BOOT_CONFIG_IFR_NVDATA);
+ ZeroMem (&CallbackInfo->HttpBootNvData, BufferSize);
+
+ Status = gHiiConfigRouting->ConfigToBlock (
+ gHiiConfigRouting,
+ Configuration,
+ (UINT8 *) &CallbackInfo->HttpBootNvData,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create a new boot option according to the configuration data.
+ //
+ HttpBootAddBootOption (
+ Private,
+ (CallbackInfo->HttpBootNvData.IpVersion == HTTP_BOOT_IP_VERSION_6) ? TRUE : FALSE,
+ CallbackInfo->HttpBootNvData.Description,
+ CallbackInfo->HttpBootNvData.Uri
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function is called to provide results data to the driver.
+ This data consists of a unique key that is used to identify
+ which data is either being passed back or being asked for.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Action Specifies the type of action taken by the browser.
+ @param[in] QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect. The format of the data tends to
+ vary based on the opcode that generated the callback.
+ @param[in] Type The type of value for the question.
+ @param[in, out] Value A pointer to the data being sent to the original
+ exporting driver.
+ @param[out] ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
+ variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+**/
+EFI_STATUS
+EFIAPI
+HttpBootFormCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN OUT EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ EFI_INPUT_KEY Key;
+ CHAR16 *Uri;
+ UINTN UriLen;
+ CHAR8 *AsciiUri;
+ HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;
+ EFI_STATUS Status;
+
+ Uri = NULL;
+ UriLen = 0;
+ AsciiUri = NULL;
+ Status = EFI_SUCCESS;
+
+ if (This == NULL || Value == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CallbackInfo = HTTP_BOOT_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);
+
+ if (Action != EFI_BROWSER_ACTION_CHANGING) {
+ return EFI_UNSUPPORTED;
+ }
+
+ switch (QuestionId) {
+ case KEY_INITIATOR_URI:
+ //
+ // Get user input URI string
+ //
+ Uri = HiiGetString (CallbackInfo->RegisteredHandle, Value->string, NULL);
+ if(Uri == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The URI should be either an empty string (for corporate environment) ,or http(s) for home environment.
+ // Pop up a message box for the unsupported URI.
+ //
+ if (StrLen (Uri) != 0) {
+ UriLen = StrLen (Uri) + 1;
+ AsciiUri = AllocateZeroPool (UriLen);
+ if (AsciiUri == NULL) {
+ FreePool (Uri);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UnicodeStrToAsciiStrS (Uri, AsciiUri, UriLen);
+
+ Status = HttpBootCheckUriScheme (AsciiUri);
+
+ if (Status == EFI_INVALID_PARAMETER) {
+
+ DEBUG ((EFI_D_ERROR, "HttpBootFormCallback: %r.\n", Status));
+
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"ERROR: Unsupported URI!",
+ L"Only supports HTTP and HTTPS",
+ NULL
+ );
+ } else if (Status == EFI_ACCESS_DENIED) {
+
+ DEBUG ((EFI_D_ERROR, "HttpBootFormCallback: %r.\n", Status));
+
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"ERROR: Unsupported URI!",
+ L"HTTP is disabled",
+ NULL
+ );
+ }
+ }
+
+ if (Uri != NULL) {
+ FreePool (Uri);
+ }
+
+ if (AsciiUri != NULL) {
+ FreePool (AsciiUri);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return Status;
+}
+
+/**
+ Initialize the configuration form.
+
+ @param[in] Private Pointer to the driver private data.
+
+ @retval EFI_SUCCESS The configuration form is initialized.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+
+**/
+EFI_STATUS
+HttpBootConfigFormInit (
+ IN HTTP_BOOT_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;
+ VENDOR_DEVICE_PATH VendorDeviceNode;
+ CHAR16 *MacString;
+ CHAR16 *OldMenuString;
+ CHAR16 MenuString[128];
+
+ CallbackInfo = &Private->CallbackInfo;
+
+ if (CallbackInfo->Initialized) {
+ return EFI_SUCCESS;
+ }
+
+ CallbackInfo->Signature = HTTP_BOOT_FORM_CALLBACK_INFO_SIGNATURE;
+
+ //
+ // Construct device path node for EFI HII Config Access protocol,
+ // which consists of controller physical device path and one hardware
+ // vendor guid node.
+ //
+ ZeroMem (&VendorDeviceNode, sizeof (VENDOR_DEVICE_PATH));
+ VendorDeviceNode.Header.Type = HARDWARE_DEVICE_PATH;
+ VendorDeviceNode.Header.SubType = HW_VENDOR_DP;
+ CopyGuid (&VendorDeviceNode.Guid, &gEfiCallerIdGuid);
+ SetDevicePathNodeLength (&VendorDeviceNode.Header, sizeof (VENDOR_DEVICE_PATH));
+ CallbackInfo->HiiVendorDevicePath = AppendDevicePathNode (
+ Private->ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode
+ );
+ if (CallbackInfo->HiiVendorDevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ CallbackInfo->ConfigAccess.ExtractConfig = HttpBootFormExtractConfig;
+ CallbackInfo->ConfigAccess.RouteConfig = HttpBootFormRouteConfig;
+ CallbackInfo->ConfigAccess.Callback = HttpBootFormCallback;
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &CallbackInfo->ChildHandle,
+ &gEfiDevicePathProtocolGuid,
+ CallbackInfo->HiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &CallbackInfo->ConfigAccess,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // Publish our HII data.
+ //
+ CallbackInfo->RegisteredHandle = HiiAddPackages (
+ &gHttpBootConfigGuid,
+ CallbackInfo->ChildHandle,
+ HttpBootDxeStrings,
+ HttpBootConfigVfrBin,
+ NULL
+ );
+ if (CallbackInfo->RegisteredHandle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ //
+ // Append MAC string in the menu help string
+ //
+ Status = NetLibGetMacString (Private->Controller, NULL, &MacString);
+ if (!EFI_ERROR (Status)) {
+ OldMenuString = HiiGetString (
+ CallbackInfo->RegisteredHandle,
+ STRING_TOKEN (STR_HTTP_BOOT_CONFIG_FORM_HELP),
+ NULL
+ );
+ UnicodeSPrint (MenuString, 128, L"%s (MAC:%s)", OldMenuString, MacString);
+ HiiSetString (
+ CallbackInfo->RegisteredHandle,
+ STRING_TOKEN (STR_HTTP_BOOT_CONFIG_FORM_HELP),
+ MenuString,
+ NULL
+ );
+
+ FreePool (MacString);
+ FreePool (OldMenuString);
+
+ CallbackInfo->Initialized = TRUE;
+ return EFI_SUCCESS;
+ }
+
+Error:
+
+ HttpBootConfigFormUnload (Private);
+ return Status;
+}
+
+/**
+ Unload the configuration form, this includes: delete all the configuration
+ entries, uninstall the form callback protocol, and free the resources used.
+ The form will only be unload completely when both IP4 and IP6 stack are stopped.
+
+ @param[in] Private Pointer to the driver private data.
+
+ @retval EFI_SUCCESS The configuration form is unloaded.
+ @retval Others Failed to unload the form.
+
+**/
+EFI_STATUS
+HttpBootConfigFormUnload (
+ IN HTTP_BOOT_PRIVATE_DATA *Private
+ )
+{
+ HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;
+
+ if (Private->Ip4Nic != NULL || Private->Ip6Nic != NULL) {
+ //
+ // Only unload the configuration form when both IP4 and IP6 stack are stopped.
+ //
+ return EFI_SUCCESS;
+ }
+
+ CallbackInfo = &Private->CallbackInfo;
+ if (CallbackInfo->ChildHandle != NULL) {
+ //
+ // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
+ //
+ gBS->UninstallMultipleProtocolInterfaces (
+ CallbackInfo->ChildHandle,
+ &gEfiDevicePathProtocolGuid,
+ CallbackInfo->HiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &CallbackInfo->ConfigAccess,
+ NULL
+ );
+ CallbackInfo->ChildHandle = NULL;
+ }
+
+ if (CallbackInfo->HiiVendorDevicePath != NULL) {
+ FreePool (CallbackInfo->HiiVendorDevicePath);
+ CallbackInfo->HiiVendorDevicePath = NULL;
+ }
+
+ if (CallbackInfo->RegisteredHandle != NULL) {
+ //
+ // Remove HII package list
+ //
+ HiiRemovePackages (CallbackInfo->RegisteredHandle);
+ CallbackInfo->RegisteredHandle = NULL;
+ }
+
+ return EFI_SUCCESS;
+}