We always need to call EfiBootManagerFreeLoadOption because the memory allocated for NewOption (description and device path) is no longer needed. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Ye Ting <ting.ye@intel.com> Reviewed-by: Sunny Wang <sunnywang@hpe.com> Reviewed-By: Wu Jiaxin <jiaxin.wu@intel.com>
		
			
				
	
	
		
			682 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			682 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Helper functions for configuring or getting the parameters relating to HTTP Boot.
 | 
						|
 | 
						|
Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
 | 
						|
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 "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.
 | 
						|
  //
 | 
						|
  UnicodeStrToAsciiStr (Uri, 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);
 | 
						|
    ASSERT (ConfigRequest != NULL);
 | 
						|
    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;
 | 
						|
  UINTN                           Index;
 | 
						|
  CHAR16                          *Uri;
 | 
						|
  HTTP_BOOT_FORM_CALLBACK_INFO    *CallbackInfo;
 | 
						|
  
 | 
						|
  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);
 | 
						|
    ASSERT (Uri != NULL);
 | 
						|
    if (Uri == NULL) {
 | 
						|
      return EFI_UNSUPPORTED;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // 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');
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Set the converted URI string back
 | 
						|
    //
 | 
						|
    HiiSetString (CallbackInfo->RegisteredHandle, Value->string, Uri, NULL);
 | 
						|
 | 
						|
    //
 | 
						|
    // The URI should be either an empty string (for corporate environment) ,or http(s) for home environment.
 | 
						|
    // Pop up a message box for other unsupported URI.
 | 
						|
    //
 | 
						|
    if ((StrLen (Uri) != 0) && (StrnCmp (Uri, L"http://", 7) != 0) && (StrnCmp (Uri, L"https://", 8) != 0)) {
 | 
						|
      CreatePopUp (
 | 
						|
        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
 | 
						|
        &Key,
 | 
						|
        L"ERROR: Unsupported URI!",
 | 
						|
        L"Only supports HTTP and HTTPS",
 | 
						|
        NULL
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool (Uri);
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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->Initilized) {
 | 
						|
    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->Initilized = 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;
 | 
						|
}
 |