+/** @file\r
+ Helper functions for configuring or getting the parameters relating to HTTP Boot.\r
+\r
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "HttpBootDxe.h"\r
+\r
+CHAR16 mHttpBootConfigStorageName[] = L"HTTP_BOOT_CONFIG_IFR_NVDATA";\r
+\r
+/**\r
+ Add new boot option for HTTP boot.\r
+\r
+ @param[in] Private Pointer to the driver private data.\r
+ @param[in] UsingIpv6 Set to TRUE if creating boot option for IPv6.\r
+ @param[in] Description The description text of the boot option.\r
+ @param[in] Uri The URI string of the boot file.\r
+ \r
+ @retval EFI_SUCCESS The boot option is created successfully.\r
+ @retval Others Failed to create new boot option.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootAddBootOption (\r
+ IN HTTP_BOOT_PRIVATE_DATA *Private,\r
+ IN BOOLEAN UsingIpv6,\r
+ IN CHAR16 *Description,\r
+ IN CHAR16 *Uri\r
+ )\r
+{\r
+ EFI_DEV_PATH *Node;\r
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
+ UINTN Length;\r
+ CHAR8 AsciiUri[URI_STR_MAX_SIZE];\r
+ CHAR16 *CurrentOrder;\r
+ EFI_STATUS Status;\r
+ UINTN OrderCount;\r
+ UINTN TargetLocation;\r
+ BOOLEAN Found;\r
+ UINT8 *TempByteBuffer;\r
+ UINT8 *TempByteStart;\r
+ UINTN DescSize;\r
+ UINTN FilePathSize;\r
+ CHAR16 OptionStr[10];\r
+ UINT16 *NewOrder;\r
+ UINTN Index;\r
+\r
+ NewOrder = NULL;\r
+ TempByteStart = NULL;\r
+ NewDevicePath = NULL;\r
+ NewOrder = NULL;\r
+ Node = NULL;\r
+ TmpDevicePath = NULL;\r
+ CurrentOrder = NULL;\r
+\r
+ if (StrLen (Description) == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Convert the scheme to all lower case.\r
+ //\r
+ for (Index = 0; Index < StrLen (Uri); Index++) {\r
+ if (Uri[Index] == L':') {\r
+ break;\r
+ }\r
+ if (Uri[Index] >= L'A' && Uri[Index] <= L'Z') {\r
+ Uri[Index] -= (CHAR16)(L'A' - L'a');\r
+ }\r
+ }\r
+\r
+ //\r
+ // Only accept http and https URI.\r
+ //\r
+ if ((StrnCmp (Uri, L"http://", 7) != 0) && (StrnCmp (Uri, L"https://", 7) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ //\r
+ // Create a new device path by appending the IP node and URI node to\r
+ // the driver's parent device path\r
+ //\r
+ if (!UsingIpv6) {\r
+ Node = AllocateZeroPool (sizeof (IPv4_DEVICE_PATH));\r
+ if (Node == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+ Node->Ipv4.Header.Type = MESSAGING_DEVICE_PATH;\r
+ Node->Ipv4.Header.SubType = MSG_IPv4_DP;\r
+ SetDevicePathNodeLength (Node, sizeof (IPv4_DEVICE_PATH));\r
+ } else {\r
+ Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH));\r
+ if (Node == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+ Node->Ipv6.Header.Type = MESSAGING_DEVICE_PATH;\r
+ Node->Ipv6.Header.SubType = MSG_IPv6_DP;\r
+ SetDevicePathNodeLength (Node, sizeof (IPv6_DEVICE_PATH));\r
+ }\r
+ TmpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);\r
+ FreePool (Node);\r
+ if (TmpDevicePath == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Update the URI node with the input boot file URI.\r
+ //\r
+ UnicodeStrToAsciiStr (Uri, AsciiUri);\r
+ Length = sizeof (EFI_DEVICE_PATH_PROTOCOL) + AsciiStrSize (AsciiUri);\r
+ Node = AllocatePool (Length);\r
+ if (Node == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ FreePool (TmpDevicePath);\r
+ goto ON_EXIT;\r
+ }\r
+ Node->DevPath.Type = MESSAGING_DEVICE_PATH;\r
+ Node->DevPath.SubType = MSG_URI_DP;\r
+ SetDevicePathNodeLength (Node, Length);\r
+ CopyMem ((UINT8*) Node + sizeof (EFI_DEVICE_PATH_PROTOCOL), AsciiUri, AsciiStrSize (AsciiUri));\r
+ NewDevicePath = AppendDevicePathNode (TmpDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);\r
+ FreePool (Node);\r
+ FreePool (TmpDevicePath);\r
+ if (NewDevicePath == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Get current "BootOrder" variable and find a free target.\r
+ //\r
+ Length = 0;\r
+ Status = GetVariable2 (\r
+ L"BootOrder",\r
+ &gEfiGlobalVariableGuid,\r
+ &CurrentOrder,\r
+ &Length \r
+ );\r
+ if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {\r
+ goto ON_EXIT;\r
+ }\r
+ OrderCount = Length / sizeof (UINT16);\r
+ Found = FALSE;\r
+ for (TargetLocation=0; TargetLocation < 0xFFFF; TargetLocation++) {\r
+ Found = TRUE;\r
+ for (Index = 0; Index < OrderCount; Index++) {\r
+ if (CurrentOrder[Index] == TargetLocation) {\r
+ Found = FALSE;\r
+ break;\r
+ }\r
+ }\r
+ if (Found) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (TargetLocation == 0xFFFF) {\r
+ DEBUG ((EFI_D_ERROR, "Could not find unused target index.\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "TargetIndex = %04x.\n", TargetLocation));\r
+ }\r
+ \r
+ //\r
+ // Construct and set the "Boot####" variable\r
+ //\r
+ DescSize = StrSize(Description);\r
+ FilePathSize = GetDevicePathSize (NewDevicePath);\r
+ TempByteBuffer = AllocateZeroPool(sizeof(EFI_LOAD_OPTION) + DescSize + FilePathSize);\r
+ if (TempByteBuffer == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ TempByteStart = TempByteBuffer;\r
+ *((UINT32 *) TempByteBuffer) = LOAD_OPTION_ACTIVE; // Attributes\r
+ TempByteBuffer += sizeof (UINT32);\r
+\r
+ *((UINT16 *) TempByteBuffer) = (UINT16)FilePathSize; // FilePathListLength\r
+ TempByteBuffer += sizeof (UINT16);\r
+\r
+ CopyMem (TempByteBuffer, Description, DescSize);\r
+ TempByteBuffer += DescSize;\r
+ CopyMem (TempByteBuffer, NewDevicePath, FilePathSize);\r
+\r
+ UnicodeSPrint (OptionStr, sizeof(OptionStr), L"%s%04x", L"Boot", TargetLocation);\r
+ Status = gRT->SetVariable (\r
+ OptionStr,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ sizeof(UINT32) + sizeof(UINT16) + DescSize + FilePathSize,\r
+ TempByteStart\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Insert into the order list and set "BootOrder" variable\r
+ //\r
+ NewOrder = AllocateZeroPool ((OrderCount + 1) * sizeof (UINT16));\r
+ if (NewOrder == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+ CopyMem(NewOrder, CurrentOrder, OrderCount * sizeof(UINT16));\r
+ NewOrder[OrderCount] = (UINT16) TargetLocation;\r
+ Status = gRT->SetVariable (\r
+ L"BootOrder",\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ ((OrderCount + 1) * sizeof (UINT16)),\r
+ NewOrder\r
+ );\r
+ \r
+\r
+ON_EXIT:\r
+\r
+ if (CurrentOrder != NULL) {\r
+ FreePool (CurrentOrder);\r
+ }\r
+ if (NewOrder != NULL) {\r
+ FreePool (NewOrder);\r
+ }\r
+ if (TempByteStart != NULL) {\r
+ FreePool (TempByteStart);\r
+ }\r
+ if (NewDevicePath != NULL) {\r
+ FreePool (NewDevicePath);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ \r
+ This function allows the caller to request the current\r
+ configuration for one or more named elements. The resulting\r
+ string is in <ConfigAltResp> format. Also, any and all alternative\r
+ configuration strings shall be appended to the end of the\r
+ current configuration string. If they are, they must appear\r
+ after the current configuration. They must contain the same\r
+ routing (GUID, NAME, PATH) as the current configuration string.\r
+ They must have an additional description indicating the type of\r
+ alternative configuration the string represents,\r
+ "ALTCFG=<StringToken>". That <StringToken> (when\r
+ converted from Hex UNICODE to binary) is a reference to a\r
+ string in the associated string pack.\r
+\r
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+\r
+ @param[in] Request A null-terminated Unicode string in\r
+ <ConfigRequest> format. Note that this\r
+ includes the routing information as well as\r
+ the configurable name / value pairs. It is\r
+ invalid for this string to be in\r
+ <MultiConfigRequest> format.\r
+\r
+ @param[out] Progress On return, points to a character in the\r
+ Request string. Points to the string's null\r
+ terminator if request was successful. Points\r
+ to the most recent "&" before the first\r
+ failing name / value pair (or the beginning\r
+ of the string if the failure is in the first\r
+ name / value pair) if the request was not successful. \r
+\r
+ @param[out] Results A null-terminated Unicode string in\r
+ <ConfigAltResp> format which has all values\r
+ filled in for the names in the Request string.\r
+ String to be allocated by the called function.\r
+\r
+ @retval EFI_SUCCESS The Results string is filled with the\r
+ values corresponding to all requested\r
+ names.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the\r
+ parts of the results that must be\r
+ stored awaiting possible future\r
+ protocols.\r
+\r
+ @retval EFI_INVALID_PARAMETER For example, passing in a NULL\r
+ for the Request parameter\r
+ would result in this type of\r
+ error. In this case, the\r
+ Progress parameter would be\r
+ set to NULL. \r
+\r
+ @retval EFI_NOT_FOUND Routing data doesn't match any\r
+ known driver. Progress set to the\r
+ first character in the routing header.\r
+ Note: There is no requirement that the\r
+ driver validate the routing data. It\r
+ must skip the <ConfigHdr> in order to\r
+ process the names.\r
+\r
+ @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set\r
+ to most recent "&" before the\r
+ error or the beginning of the\r
+ string.\r
+\r
+ @retval EFI_INVALID_PARAMETER Unknown name. Progress points\r
+ to the & before the name in\r
+ question.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpBootFormExtractConfig (\r
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ IN CONST EFI_STRING Request,\r
+ OUT EFI_STRING *Progress,\r
+ OUT EFI_STRING *Results\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+ HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;\r
+ EFI_STRING ConfigRequestHdr;\r
+ EFI_STRING ConfigRequest;\r
+ BOOLEAN AllocatedRequest;\r
+ UINTN Size;\r
+\r
+ if (Progress == NULL || Results == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *Progress = Request;\r
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gHttpBootConfigGuid, mHttpBootConfigStorageName)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ \r
+ ConfigRequestHdr = NULL;\r
+ ConfigRequest = NULL;\r
+ AllocatedRequest = FALSE;\r
+ Size = 0;\r
+\r
+ CallbackInfo = HTTP_BOOT_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);\r
+ //\r
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()\r
+ //\r
+ BufferSize = sizeof (HTTP_BOOT_CONFIG_IFR_NVDATA);\r
+ ZeroMem (&CallbackInfo->HttpBootNvData, BufferSize);\r
+\r
+ ConfigRequest = Request;\r
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
+ //\r
+ // Request has no request element, construct full request string.\r
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator\r
+ //\r
+ ConfigRequestHdr = HiiConstructConfigHdr (&gHttpBootConfigGuid, mHttpBootConfigStorageName, CallbackInfo->ChildHandle);\r
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
+ ConfigRequest = AllocateZeroPool (Size);\r
+ ASSERT (ConfigRequest != NULL);\r
+ AllocatedRequest = TRUE;\r
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);\r
+ FreePool (ConfigRequestHdr);\r
+ }\r
+\r
+ Status = gHiiConfigRouting->BlockToConfig (\r
+ gHiiConfigRouting,\r
+ ConfigRequest,\r
+ (UINT8 *) &CallbackInfo->HttpBootNvData,\r
+ BufferSize,\r
+ Results,\r
+ Progress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ //\r
+ // Free the allocated config request string.\r
+ //\r
+ if (AllocatedRequest) {\r
+ FreePool (ConfigRequest);\r
+ ConfigRequest = NULL;\r
+ }\r
+ //\r
+ // Set Progress string to the original request string.\r
+ //\r
+ if (Request == NULL) {\r
+ *Progress = NULL;\r
+ } else if (StrStr (Request, L"OFFSET") == NULL) {\r
+ *Progress = Request + StrLen (Request);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ \r
+ This function applies changes in a driver's configuration.\r
+ Input is a Configuration, which has the routing data for this\r
+ driver followed by name / value configuration pairs. The driver\r
+ must apply those pairs to its configurable storage. If the\r
+ driver's configuration is stored in a linear block of data\r
+ and the driver's name / value pairs are in <BlockConfig>\r
+ format, it may use the ConfigToBlock helper function (above) to\r
+ simplify the job.\r
+\r
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+\r
+ @param[in] Configuration A null-terminated Unicode string in\r
+ <ConfigString> format. \r
+ \r
+ @param[out] Progress A pointer to a string filled in with the\r
+ offset of the most recent '&' before the\r
+ first failing name / value pair (or the\r
+ beginning of the string if the failure\r
+ is in the first name / value pair) or\r
+ the terminating NULL if all was\r
+ successful.\r
+\r
+ @retval EFI_SUCCESS The results have been distributed or are\r
+ awaiting distribution.\r
+ \r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the\r
+ parts of the results that must be\r
+ stored awaiting possible future\r
+ protocols.\r
+ \r
+ @retval EFI_INVALID_PARAMETERS Passing in a NULL for the\r
+ Results parameter would result\r
+ in this type of error.\r
+ \r
+ @retval EFI_NOT_FOUND Target for the specified routing data\r
+ was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpBootFormRouteConfig (\r
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ IN CONST EFI_STRING Configuration,\r
+ OUT EFI_STRING *Progress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+ HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;\r
+ HTTP_BOOT_PRIVATE_DATA *Private;\r
+\r
+ if (Progress == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ *Progress = Configuration;\r
+\r
+ if (Configuration == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check routing data in <ConfigHdr>.\r
+ // Note: there is no name for Name/Value storage, only GUID will be checked\r
+ //\r
+ if (!HiiIsConfigHdrMatch (Configuration, &gHttpBootConfigGuid, mHttpBootConfigStorageName)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ CallbackInfo = HTTP_BOOT_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);\r
+ Private = HTTP_BOOT_PRIVATE_DATA_FROM_CALLBACK_INFO (CallbackInfo);\r
+ \r
+ BufferSize = sizeof (HTTP_BOOT_CONFIG_IFR_NVDATA);\r
+ ZeroMem (&CallbackInfo->HttpBootNvData, BufferSize);\r
+\r
+ Status = gHiiConfigRouting->ConfigToBlock (\r
+ gHiiConfigRouting,\r
+ Configuration,\r
+ (UINT8 *) &CallbackInfo->HttpBootNvData,\r
+ &BufferSize,\r
+ Progress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Create a new boot option according to the configuration data.\r
+ //\r
+ Status = HttpBootAddBootOption (\r
+ Private,\r
+ (CallbackInfo->HttpBootNvData.IpVersion == HTTP_BOOT_IP_VERSION_6) ? TRUE : FALSE,\r
+ CallbackInfo->HttpBootNvData.Description,\r
+ CallbackInfo->HttpBootNvData.Uri\r
+ );\r
+ \r
+ return Status;\r
+}\r
+\r
+/**\r
+ \r
+ This function is called to provide results data to the driver.\r
+ This data consists of a unique key that is used to identify\r
+ which data is either being passed back or being asked for.\r
+\r
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param[in] Action Specifies the type of action taken by the browser.\r
+ @param[in] QuestionId A unique value which is sent to the original\r
+ exporting driver so that it can identify the type\r
+ of data to expect. The format of the data tends to \r
+ vary based on the opcode that generated the callback.\r
+ @param[in] Type The type of value for the question.\r
+ @param[in, out] Value A pointer to the data being sent to the original\r
+ exporting driver.\r
+ @param[out] ActionRequest On return, points to the action requested by the\r
+ callback function.\r
+\r
+ @retval EFI_SUCCESS The callback successfully handled the action.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the\r
+ variable and its data.\r
+ @retval EFI_DEVICE_ERROR The variable could not be saved.\r
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the\r
+ callback.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpBootFormCallback (\r
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ IN EFI_BROWSER_ACTION Action,\r
+ IN EFI_QUESTION_ID QuestionId,\r
+ IN UINT8 Type,\r
+ IN OUT EFI_IFR_TYPE_VALUE *Value,\r
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Initialize the configuration form.\r
+\r
+ @param[in] Private Pointer to the driver private data.\r
+\r
+ @retval EFI_SUCCESS The configuration form is initialized.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootConfigFormInit (\r
+ IN HTTP_BOOT_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;\r
+ VENDOR_DEVICE_PATH VendorDeviceNode;\r
+ EFI_SERVICE_BINDING_PROTOCOL *HttpSb;\r
+ CHAR16 *MacString;\r
+ CHAR16 *OldMenuString;\r
+ CHAR16 MenuString[128];\r
+\r
+ CallbackInfo = &Private->CallbackInfo;\r
+\r
+ if (CallbackInfo->Initilized) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ \r
+ CallbackInfo->Signature = HTTP_BOOT_FORM_CALLBACK_INFO_SIGNATURE;\r
+\r
+ //\r
+ // Construct device path node for EFI HII Config Access protocol,\r
+ // which consists of controller physical device path and one hardware\r
+ // vendor guid node.\r
+ //\r
+ ZeroMem (&VendorDeviceNode, sizeof (VENDOR_DEVICE_PATH));\r
+ VendorDeviceNode.Header.Type = HARDWARE_DEVICE_PATH;\r
+ VendorDeviceNode.Header.SubType = HW_VENDOR_DP;\r
+ CopyGuid (&VendorDeviceNode.Guid, &gEfiCallerIdGuid);\r
+ SetDevicePathNodeLength (&VendorDeviceNode.Header, sizeof (VENDOR_DEVICE_PATH));\r
+ CallbackInfo->HiiVendorDevicePath = AppendDevicePathNode (\r
+ Private->ParentDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode\r
+ );\r
+ if (CallbackInfo->HiiVendorDevicePath == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ CallbackInfo->ConfigAccess.ExtractConfig = HttpBootFormExtractConfig;\r
+ CallbackInfo->ConfigAccess.RouteConfig = HttpBootFormRouteConfig;\r
+ CallbackInfo->ConfigAccess.Callback = HttpBootFormCallback;\r
+ \r
+ //\r
+ // Install Device Path Protocol and Config Access protocol to driver handle.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &CallbackInfo->ChildHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ CallbackInfo->HiiVendorDevicePath,\r
+ &gEfiHiiConfigAccessProtocolGuid,\r
+ &CallbackInfo->ConfigAccess,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Open the Parent Handle for the child\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Private->Controller,\r
+ &gEfiHttpServiceBindingProtocolGuid,\r
+ (VOID **) &HttpSb,\r
+ Private->Image,\r
+ CallbackInfo->ChildHandle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+\r
+ //\r
+ // Publish our HII data.\r
+ //\r
+ CallbackInfo->RegisteredHandle = HiiAddPackages (\r
+ &gHttpBootConfigGuid,\r
+ CallbackInfo->ChildHandle,\r
+ HttpBootDxeStrings,\r
+ HttpBootConfigVfrBin,\r
+ NULL\r
+ );\r
+ if (CallbackInfo->RegisteredHandle == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ //\r
+ // Append MAC string in the menu help string\r
+ //\r
+ Status = NetLibGetMacString (Private->Controller, Private->Image, &MacString);\r
+ if (!EFI_ERROR (Status)) {\r
+ OldMenuString = HiiGetString (\r
+ CallbackInfo->RegisteredHandle, \r
+ STRING_TOKEN (STR_HTTP_BOOT_CONFIG_FORM_HELP), \r
+ NULL\r
+ );\r
+ UnicodeSPrint (MenuString, 128, L"%s (MAC:%s)", OldMenuString, MacString);\r
+ HiiSetString (\r
+ CallbackInfo->RegisteredHandle, \r
+ STRING_TOKEN (STR_HTTP_BOOT_CONFIG_FORM_HELP), \r
+ MenuString, \r
+ NULL\r
+ );\r
+ \r
+ FreePool (MacString);\r
+ FreePool (OldMenuString);\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ \r
+Error:\r
+\r
+ HttpBootConfigFormUnload (Private);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Unload the configuration form, this includes: delete all the configuration\r
+ entries, uninstall the form callback protocol, and free the resources used.\r
+\r
+ @param[in] Private Pointer to the driver private data.\r
+\r
+ @retval EFI_SUCCESS The configuration form is unloaded.\r
+ @retval Others Failed to unload the form.\r
+\r
+**/\r
+EFI_STATUS\r
+HttpBootConfigFormUnload (\r
+ IN HTTP_BOOT_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;\r
+\r
+ CallbackInfo = &Private->CallbackInfo;\r
+ if (CallbackInfo->ChildHandle != NULL) {\r
+ //\r
+ // Close the child handle\r
+ //\r
+ gBS->CloseProtocol (\r
+ Private->Controller,\r
+ &gEfiHttpServiceBindingProtocolGuid,\r
+ Private->Image,\r
+ CallbackInfo->ChildHandle\r
+ );\r
+ \r
+ //\r
+ // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL\r
+ //\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ CallbackInfo->ChildHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ CallbackInfo->HiiVendorDevicePath,\r
+ &gEfiHiiConfigAccessProtocolGuid,\r
+ &CallbackInfo->ConfigAccess,\r
+ NULL\r
+ );\r
+ CallbackInfo->ChildHandle = NULL;\r
+ }\r
+\r
+ if (CallbackInfo->HiiVendorDevicePath != NULL) {\r
+ FreePool (CallbackInfo->HiiVendorDevicePath);\r
+ CallbackInfo->HiiVendorDevicePath = NULL;\r
+ }\r
+\r
+ if (CallbackInfo->RegisteredHandle != NULL) {\r
+ //\r
+ // Remove HII package list\r
+ //\r
+ HiiRemovePackages (CallbackInfo->RegisteredHandle);\r
+ CallbackInfo->RegisteredHandle = NULL;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r