1737 lines
61 KiB
C
1737 lines
61 KiB
C
/** @file
|
|
This file contains source for MEBx Setup initialization and support.
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 2017 - 2021 Intel Corporation.
|
|
|
|
The source code contained or described herein and all documents related to the
|
|
source code ("Material") are owned by Intel Corporation or its suppliers or
|
|
licensors. Title to the Material remains with Intel Corporation or its suppliers
|
|
and licensors. The Material may contain trade secrets and proprietary and
|
|
confidential information of Intel Corporation and its suppliers and licensors,
|
|
and is protected by worldwide copyright and trade secret laws and treaty
|
|
provisions. No part of the Material may be used, copied, reproduced, modified,
|
|
published, uploaded, posted, transmitted, distributed, or disclosed in any way
|
|
without Intel's prior express written permission.
|
|
|
|
No license under any patent, copyright, trade secret or other intellectual
|
|
property right is granted to or conferred upon you by disclosure or delivery
|
|
of the Materials, either expressly, by implication, inducement, estoppel or
|
|
otherwise. Any license under such intellectual property rights must be
|
|
express and approved by Intel in writing.
|
|
|
|
Unless otherwise agreed by Intel in writing, you may not remove or alter
|
|
this notice or any other notice embedded in Materials by Intel or
|
|
Intel's suppliers or licensors in any way.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/HiiLib.h>
|
|
#include <Library/HobLib.h>
|
|
#include <Library/DxeMeLib.h>
|
|
#include <Library/PrintLib.h>
|
|
#include <Library/DxeMebxWrapperLib.h>
|
|
#include <Library/DxeMebxDisplayWrapperLib.h>
|
|
#include <Protocol/MebxDisplayProtocol.h>
|
|
#include <Protocol/DevicePath.h>
|
|
#include <Protocol/HiiConfigRouting.h>
|
|
#include <Protocol/HiiConfigAccess.h>
|
|
#include <Protocol/PlatformSpecificResetFilter.h>
|
|
#include <PchResetPlatformSpecific.h>
|
|
#include <MebxSetup.h>
|
|
#include <MebxSetupVariable.h>
|
|
#include <MebxSettings.h>
|
|
#include <MeBiosPayloadHob.h>
|
|
|
|
///
|
|
/// Global variables
|
|
///
|
|
|
|
#define MEBX_CFG_VARIABLE_NAME L"MebxCfg"
|
|
|
|
// These variables definitions are autogenerated by build system
|
|
extern UINT8 MebxSetupVfrBin[];
|
|
extern UINT8 MebxSetupStrings[];
|
|
|
|
MEBX_CONFIGURATION gMebxConfiguration = {0};
|
|
EFI_GUID gMebxFormSetGuid = MEBX_FORMSET_GUID;
|
|
EFI_HII_HANDLE mMebxHiiHandle;
|
|
EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting;
|
|
EFI_HII_CONFIG_ACCESS_PROTOCOL gMebxConfigAccess;
|
|
|
|
typedef struct {
|
|
VENDOR_DEVICE_PATH VendorDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL End;
|
|
} HII_VENDOR_DEVICE_PATH;
|
|
|
|
HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
|
|
{
|
|
{
|
|
HARDWARE_DEVICE_PATH,
|
|
HW_VENDOR_DP,
|
|
{
|
|
(UINT8) (sizeof (VENDOR_DEVICE_PATH)),
|
|
(UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
|
|
}
|
|
},
|
|
MEBX_FORMSET_GUID
|
|
},
|
|
{
|
|
END_DEVICE_PATH_TYPE,
|
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
{
|
|
(UINT8) (END_DEVICE_PATH_LENGTH),
|
|
(UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
|
|
}
|
|
}
|
|
};
|
|
|
|
#define NET_IP_ADDR_ALL_ZEROS(ip) ((ip) == (0x00000000))
|
|
#define NET_IP_ADDR_IN_ZERO_SUBNET(ip) (((ip) & 0xff000000) == 0x00000000)
|
|
#define NET_IP_ADDR_IN_LOOPBACK_SUBNET(ip) (((ip) & 0xff000000) == 0x7f000000)
|
|
#define NET_IP_ADDR_IN_CLASS_D(ip) (((ip) >= 0xe0000000) && ((ip) <= 0xefffffff))
|
|
#define NET_IP_ADDR_IN_CLASS_E(ip) (((ip) >= 0xf0000000) && ((ip) <= 0xffffffff))
|
|
#define NET_IP_ADDR_IN_MULTICAST_RANGE(ip) NET_IP_ADDR_IN_CLASS_D(ip)
|
|
#define NET_IP_ADDR_IN_RESERVED_RANGE(ip) NET_IP_ADDR_IN_CLASS_E(ip)
|
|
#define NET_IP_ADDR_NETMASK_VALID_RANGE(mask) (((mask) >= 0xc0000000) && ((mask) <= 0xFFFFFFFE))
|
|
#define NET_IP_ADDR_NO_HOST_ID(ip,mask) (((ip) & (mask)) == (ip))
|
|
#define NET_IP_ADDR_IS_BROADCAST(ip,mask) (((ip) | (mask))== 0xffffffff)
|
|
|
|
#define SHOW_VAR_DIFF(Struct1, Struct2, Field) {\
|
|
if (Struct1->Field != Struct2->Field) {\
|
|
DEBUG ((DEBUG_INFO, "Updating: " #Field "=%x->%x\n", Struct1->Field, Struct2->Field));\
|
|
}\
|
|
}
|
|
#define SHOW_STRING_DIFF(Struct1, Struct2, Field) {\
|
|
if (StrCmp (Struct1->Field, Struct2->Field)) {\
|
|
DEBUG ((DEBUG_INFO, "Updating: " #Field "=%s->%s\n", Struct1->Field, Struct2->Field));\
|
|
}\
|
|
}
|
|
|
|
#define FLAG_OFFSET(x) ((OFFSET_OF (MEBX_CONFIGURATION, x) ))
|
|
#define SET_IN_BROWSER(x,y) ((SetVariableInBrowser(&(x.y),FLAG_OFFSET(y),sizeof(x.y))))
|
|
|
|
#define MEBX_STATE_UNDEFINED 0xFF
|
|
#define MAX_SINGLE_REQUEST_STRING_LENGTH 30
|
|
|
|
/**
|
|
Promote next platform reset to Global type. Required after changing certain settings in MEBX.
|
|
**/
|
|
VOID
|
|
ScheduleGlobalReset (
|
|
VOID
|
|
);
|
|
|
|
/**
|
|
When called from a setup callback, changes value of one variable inside MebxConfig.
|
|
This is a wrapper for HiiSetBrowserData that hides the complexity of preparing Request string.
|
|
|
|
@param[in] Value new value for the variable
|
|
@param[in] Offset offset of the variable inside MebxConfig structure
|
|
@param[in] Size size in bytes of the variable
|
|
**/
|
|
VOID
|
|
SetVariableInBrowser (
|
|
IN VOID *Value,
|
|
IN UINT32 Offset,
|
|
IN UINT32 Size
|
|
)
|
|
{
|
|
CHAR16 RequestString[MAX_SINGLE_REQUEST_STRING_LENGTH];
|
|
UINT8 MebxSetup[sizeof (MEBX_CONFIGURATION)];
|
|
|
|
ASSERT (Offset + Size <= sizeof (MEBX_CONFIGURATION));
|
|
UnicodeSPrint (RequestString, MAX_SINGLE_REQUEST_STRING_LENGTH * sizeof (UINT16), L"&OFFSET=%x&WIDTH=%x", Offset, Size);
|
|
CopyMem (&(MebxSetup[Offset]), Value, Size);
|
|
HiiSetBrowserData (&gMebxFormSetGuid, MEBX_CFG_VARIABLE_NAME, sizeof (MEBX_CONFIGURATION), MebxSetup, RequestString);
|
|
}
|
|
|
|
/**
|
|
When called from a setup callback, retrieves a value of one variable inside MebxConfig.
|
|
This is a wrapper for HiiGetBrowserData that hides the complexity of preparing Request string.
|
|
|
|
@param[in] Value new value for the variable
|
|
@param[in] Offset offset of the variable inside MebxConfig structure
|
|
@param[in] Size size in bytes of the variable
|
|
**/
|
|
VOID
|
|
GetVariableFromBrowser (
|
|
IN UINT32 Offset,
|
|
IN UINT32 Size,
|
|
OUT VOID *Value
|
|
)
|
|
{
|
|
UINT8 MebxSetup[sizeof (MEBX_CONFIGURATION)];
|
|
BOOLEAN Result;
|
|
|
|
ASSERT (Offset + Size <= sizeof (MEBX_CONFIGURATION));
|
|
Result = HiiGetBrowserData (&gMebxFormSetGuid, MEBX_CFG_VARIABLE_NAME, sizeof (MEBX_CONFIGURATION), MebxSetup);
|
|
DEBUG ((DEBUG_INFO, "GetVariableFromBrowser result %d\n", Result));
|
|
CopyMem (Value, &(MebxSetup[Offset]), Size);
|
|
}
|
|
|
|
/**
|
|
When called from a setup callback, sets one exposure flag inside MebxConfig to new value
|
|
|
|
@param[in] Offset Offset of the variable inside MebxConfig structure
|
|
@param[in] Flag New value for the flag
|
|
**/
|
|
VOID
|
|
SetExposureFlag (
|
|
IN UINT32 Offset,
|
|
IN UINT8 Flag
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "SetExposureFlag at %x to %x\n", Offset, Flag));
|
|
SetVariableInBrowser (&Flag, Offset ,1);
|
|
}
|
|
|
|
/**
|
|
Shows differences between current and new configuration
|
|
|
|
@param[in] Cfg1 Pointer to structure holding current MEBx configuration.
|
|
@param[in] Cfg2 Pointer to structure holding new MEBx configuration.
|
|
**/
|
|
VOID
|
|
ShowConfigDiff (
|
|
IN MEBX_CONFIGURATION *Cfg1,
|
|
IN MEBX_CONFIGURATION *Cfg2
|
|
)
|
|
{
|
|
UINT8 HashNumber;
|
|
|
|
DEBUG ((DEBUG_INFO, "\n\n***** DIFF ***** DIFF ***** DIFF ***** DIFF ***** DIFF *****\n"));
|
|
SHOW_VAR_DIFF (Cfg1, Cfg2, ShowError);
|
|
SHOW_VAR_DIFF (Cfg1, Cfg2, NetAccess);
|
|
SHOW_VAR_DIFF (Cfg1, Cfg2, MeOnHostSlpStates);
|
|
SHOW_VAR_DIFF (Cfg1, Cfg2, IdleTimeout);
|
|
SHOW_VAR_DIFF (Cfg1, Cfg2, PwdPolicy);
|
|
SHOW_VAR_DIFF (Cfg1, Cfg2, AmtState);
|
|
SHOW_VAR_DIFF (Cfg1, Cfg2, SolEnable);
|
|
SHOW_VAR_DIFF (Cfg1, Cfg2, KvmEnable);
|
|
SHOW_VAR_DIFF (Cfg1, Cfg2, UserOptIn);
|
|
SHOW_VAR_DIFF (Cfg1, Cfg2, RemoteItOptInConfig);
|
|
SHOW_VAR_DIFF (Cfg1, Cfg2, StorageRedirEnable);
|
|
SHOW_VAR_DIFF (Cfg1, Cfg2, StorageRedirEnable);
|
|
SHOW_STRING_DIFF (Cfg1, Cfg2, HostDomainName);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, FqdnType);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, DynamicDnsUpdate);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, UpdateInterval);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, Ttl);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, DhcpMode);
|
|
SHOW_STRING_DIFF (Cfg1, Cfg2, Ipv4Addr);
|
|
SHOW_STRING_DIFF (Cfg1, Cfg2, Ipv4MaskAddr);
|
|
SHOW_STRING_DIFF (Cfg1, Cfg2, Ipv4GatewayAddr);
|
|
SHOW_STRING_DIFF (Cfg1, Cfg2, Ipv4PrefDnsAddr);
|
|
SHOW_STRING_DIFF (Cfg1, Cfg2, Ipv4AltDnsAddr);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, ProvServerPort);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, TlsPpkRemoteConfig);
|
|
SHOW_STRING_DIFF (Cfg1, Cfg2, PkiDnsSuffix);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, PrivacyLevel);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, LanLessPlatform);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, NumberOfPowerPkgs);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, MOffOverride);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, SouthClinkState);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, GlobalExposure);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, AmtStateExposure);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, AmtSubmenuExposure);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, KvmExposure);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, ProvisioningState);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, OptInConfigExposure);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, RemoteItOptInConfigExposure);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, AddrMaskInvalid);
|
|
SHOW_VAR_DIFF(Cfg1, Cfg2, NoDefaultHashes);
|
|
for (HashNumber = 0; HashNumber < MAX_HASH_ENTRIES; HashNumber++) {
|
|
if (Cfg1->HashValid[HashNumber] != Cfg2->HashValid[HashNumber]) {
|
|
DEBUG ((DEBUG_INFO, "HashValid=%d->%d\n",Cfg1->HashValid[HashNumber], Cfg2->HashValid[HashNumber]));
|
|
}
|
|
}
|
|
DEBUG ((DEBUG_INFO, "***** END ***** END ***** END ***** END ***** END *****\n"));
|
|
}
|
|
|
|
/**
|
|
Show current MEBx configuration.
|
|
|
|
@param[in] Cfg Pointer to structure holding current MEBx configuration.
|
|
**/
|
|
VOID
|
|
ShowConfig (
|
|
IN MEBX_CONFIGURATION *Cfg
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "ShowError=%x\n",Cfg->ShowError));
|
|
DEBUG ((DEBUG_INFO, "NetAccess=%x\n",Cfg->NetAccess));
|
|
DEBUG ((DEBUG_INFO, "MeOnHostSlpStates=%x\n",Cfg->MeOnHostSlpStates));
|
|
DEBUG ((DEBUG_INFO, "IdleTimeout=%x\n",Cfg->IdleTimeout));
|
|
DEBUG ((DEBUG_INFO, "PwdPolicy=%x\n",Cfg->PwdPolicy));
|
|
DEBUG ((DEBUG_INFO, "AmtState=%x\n",Cfg->AmtState));
|
|
DEBUG ((DEBUG_INFO, "SolEnable=%x\n",Cfg->SolEnable));
|
|
DEBUG ((DEBUG_INFO, "StorageRedirEnable=%x\n",Cfg->StorageRedirEnable));
|
|
DEBUG ((DEBUG_INFO, "KvmEnable=%x\n",Cfg->KvmEnable));
|
|
DEBUG ((DEBUG_INFO, "UserOptIn=%x\n",Cfg->UserOptIn));
|
|
DEBUG ((DEBUG_INFO, "RemoteItOptInConfig=%x\n",Cfg->RemoteItOptInConfig));
|
|
DEBUG ((DEBUG_INFO, "HostDomainName=%s\n",Cfg->HostDomainName));
|
|
DEBUG ((DEBUG_INFO, "FqdnType=%x\n",Cfg->FqdnType));
|
|
DEBUG ((DEBUG_INFO, "DynamicDnsUpdate=%x\n",Cfg->DynamicDnsUpdate));
|
|
DEBUG ((DEBUG_INFO, "UpdateInterval=%x\n",Cfg->UpdateInterval));
|
|
DEBUG ((DEBUG_INFO, "Ttl=%x\n",Cfg->Ttl));
|
|
DEBUG ((DEBUG_INFO, "DhcpMode=%x\n",Cfg->DhcpMode));
|
|
DEBUG ((DEBUG_INFO, "Ipv4Addr=%s\n",Cfg->Ipv4Addr));
|
|
DEBUG ((DEBUG_INFO, "Ipv4MaskAddr=%s\n",Cfg->Ipv4MaskAddr));
|
|
DEBUG ((DEBUG_INFO, "Ipv4GatewayAddr=%s\n",Cfg->Ipv4GatewayAddr));
|
|
DEBUG ((DEBUG_INFO, "Ipv4PrefDnsAddr=%s\n",Cfg->Ipv4PrefDnsAddr));
|
|
DEBUG ((DEBUG_INFO, "Ipv4AltDnsAddr=%s\n",Cfg->Ipv4AltDnsAddr));
|
|
DEBUG ((DEBUG_INFO, "ProvServerPort=%x\n",Cfg->ProvServerPort));
|
|
DEBUG ((DEBUG_INFO, "TlsPpkRemoteConfig=%x\n",Cfg->TlsPpkRemoteConfig));
|
|
DEBUG ((DEBUG_INFO, "PkiDnsSuffix=%s\n",Cfg->PkiDnsSuffix));
|
|
DEBUG ((DEBUG_INFO, "PrivacyLevel=%x\n",Cfg->PrivacyLevel));
|
|
DEBUG ((DEBUG_INFO, "LanLessPlatform=%x\n",Cfg->LanLessPlatform));
|
|
DEBUG ((DEBUG_INFO, "NumberOfPowerPkgs=%x\n",Cfg->NumberOfPowerPkgs));
|
|
DEBUG ((DEBUG_INFO, "NoDefaultHashes=%x\n",Cfg->NoDefaultHashes));
|
|
DEBUG ((DEBUG_INFO, "MOffOverride=%x\n",Cfg->MOffOverride));
|
|
DEBUG ((DEBUG_INFO, "SouthClinkState=%x\n",Cfg->SouthClinkState));
|
|
DEBUG ((DEBUG_INFO, "GlobalExposure=%x\n",Cfg->GlobalExposure));
|
|
DEBUG ((DEBUG_INFO, "AmtStateExposure=%x\n",Cfg->AmtStateExposure));
|
|
DEBUG ((DEBUG_INFO, "AmtSubmenuExposure=%x\n",Cfg->AmtSubmenuExposure));
|
|
DEBUG ((DEBUG_INFO, "KvmExposure=%x\n",Cfg->KvmExposure));
|
|
DEBUG ((DEBUG_INFO, "ProvisioningState=%x\n",Cfg->ProvisioningState));
|
|
DEBUG ((DEBUG_INFO, "OptInConfigExposure=%x\n",Cfg->OptInConfigExposure));
|
|
DEBUG ((DEBUG_INFO, "RemoteItOptInConfigExposure=%x\n",Cfg->RemoteItOptInConfigExposure));
|
|
DEBUG ((DEBUG_INFO, "AddrMaskInvalid=%x\n",Cfg->AddrMaskInvalid));
|
|
DEBUG ((DEBUG_INFO, "FwVersionMajor=%x\n",Cfg->FwVersionMajor));
|
|
}
|
|
|
|
/**
|
|
Convert a NULL-terminad Unicode string to IPv4 address stored into 32 bits.
|
|
|
|
@param[in] AddrIn Pointer to a Null-terminated Unicode string.
|
|
@param[out] Erorr Error status:
|
|
BAD_IP_ADDR - string isn't in the correct format
|
|
INPUT_OK - address was translated successfully
|
|
|
|
@return converted IPv4 address
|
|
**/
|
|
UINT32
|
|
Ipv4UnicodeToInteger (
|
|
IN CHAR16 *AddrIn,
|
|
OUT UINT32 *Error
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
IPv4_ADDRESS Ipv4;
|
|
UINT32 UintAddress;
|
|
UINT8 Prefix;
|
|
|
|
Status = StrToIpv4Address (AddrIn, NULL, &Ipv4, &Prefix);
|
|
if (RETURN_ERROR (Status) || (Prefix != MAX_UINT8)) {
|
|
*Error = BAD_IP_ADDR;
|
|
return 0;
|
|
}
|
|
|
|
UintAddress = (Ipv4.Addr[0] << 24) | (Ipv4.Addr[1] << 16) | (Ipv4.Addr[2] << 8) | Ipv4.Addr[3];
|
|
DEBUG ((DEBUG_INFO, "[MEBx] %a, %s -> 0x%08X\n", __FUNCTION__, AddrIn, UintAddress));
|
|
*Error = INPUT_OK;
|
|
|
|
return UintAddress;
|
|
}
|
|
|
|
/**
|
|
Checks if input string is a valid hostname
|
|
Hostname is a series of labels separated by dots. Label may consist of letters, digits and hyphens
|
|
A hyphen may not be the first or last character of label
|
|
Hostname must be no longer than 255 characters. Each label must be no longer than 63.
|
|
Last label may be empty - in other words hostname may end with a dot
|
|
|
|
@param[in] Addr Host and Domain name to verify
|
|
|
|
@return Error Code
|
|
**/
|
|
UINT32
|
|
ValidateHostDomainName (
|
|
IN CHAR8 *Name
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
UINT32 LabelLength;
|
|
UINT32 HostnameLength;
|
|
BOOLEAN Dot;
|
|
BOOLEAN Hyphen;
|
|
|
|
Index = 0;
|
|
Dot = TRUE;
|
|
LabelLength = 0;
|
|
HostnameLength = 0;
|
|
Hyphen = FALSE;
|
|
|
|
DEBUG ((DEBUG_INFO, "ValidateHostDomainName: %a\n", Name));
|
|
|
|
while (Name[Index] != '\0') {
|
|
if (!((Name[Index] >= 'a' && Name[Index] <= 'z') ||
|
|
(Name[Index] >= 'A' && Name[Index] <= 'Z') ||
|
|
(Name[Index] >= '0' && Name[Index] <= '9') ||
|
|
(Name[Index] == '-' || Name[Index] == '.'))) {
|
|
DEBUG ((DEBUG_ERROR, "HDN_INVALID_CHARACTER %d\n", Index));
|
|
return HDN_INVALID_CHARACTER;
|
|
}
|
|
|
|
if (Name[Index] == '.') {
|
|
if (Dot) {
|
|
DEBUG ((DEBUG_ERROR, "HDN_BAD_DOT %d\n", Index));
|
|
return HDN_BAD_DOT;
|
|
}
|
|
if (Hyphen) {
|
|
DEBUG ((DEBUG_ERROR, "HDN_BAD_HYPHEN %d\n", Index));
|
|
return HDN_BAD_HYPHEN;
|
|
}
|
|
if (HostnameLength == 0) {
|
|
HostnameLength = Index;
|
|
}
|
|
Dot = TRUE;
|
|
Hyphen = FALSE;
|
|
LabelLength = 0;
|
|
} else if (Name[Index] == '-') {
|
|
if (Hyphen || LabelLength == 0 || Dot) {
|
|
DEBUG ((DEBUG_ERROR, "HDN_BAD_HYPHEN %d\n", Index));
|
|
return HDN_BAD_HYPHEN;
|
|
}
|
|
Dot = FALSE;
|
|
Hyphen = TRUE;
|
|
LabelLength++;
|
|
} else {
|
|
Dot = FALSE;
|
|
Hyphen = FALSE;
|
|
LabelLength++;
|
|
}
|
|
|
|
if (Index - HostnameLength > 191) {
|
|
DEBUG ((DEBUG_ERROR, "HDN_DOMAIN_TOO_LONG %d\n", Index));
|
|
return HDN_DOMAIN_TOO_LONG;
|
|
}
|
|
if (LabelLength > 63) {
|
|
DEBUG ((DEBUG_ERROR, "HDN_LABEL_TOO_LONG %d\n", Index));
|
|
return HDN_LABEL_TOO_LONG;
|
|
}
|
|
if (Index > 253) {
|
|
DEBUG ((DEBUG_ERROR, "HDN_NAME_TOO_LONG %d\n", Index));
|
|
return HDN_NAME_TOO_LONG;
|
|
}
|
|
Index++;
|
|
}
|
|
if (Hyphen) {
|
|
DEBUG ((DEBUG_ERROR, "HDN_BAD_HYPHEN %d\n", Index));
|
|
return HDN_BAD_HYPHEN;
|
|
}
|
|
return INPUT_OK;
|
|
}
|
|
|
|
/**
|
|
IPv4 Mask must have some highest bits set, then remaining bits all clear. Zeroes and ones must not be interleaved
|
|
|
|
@param[in] Addr IP Address to verify
|
|
|
|
@retval TRUE Address is valid
|
|
@retval FALSE Adresss is invalid.
|
|
**/
|
|
BOOLEAN
|
|
IsValidIpMask (
|
|
IN UINT32 Addr
|
|
)
|
|
{
|
|
if (!NET_IP_ADDR_NETMASK_VALID_RANGE (Addr)) {
|
|
DEBUG ((DEBUG_ERROR, "%a - netmask 0x%08x is in invalid range\n", __FUNCTION__, Addr));
|
|
return FALSE;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "IsCorrectIpMask (%x):%x,%x->%x\n",Addr, ~Addr, (~Addr)+1, (((~Addr) & ((~Addr)+1)) == 0) ));
|
|
if (((~Addr) & ((~Addr)+1)) == 0) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Function verifies if Addr:Mask combination produces broadcast address (unmasked bits of addr == all zeroes or all ones)
|
|
|
|
@param[in] Addr IP Address to verify
|
|
@param[in] Mask IP Mask to verify
|
|
|
|
|
|
@retval TRUE Address is unicast
|
|
@retval FALSE Adresss is broadcast.
|
|
**/
|
|
BOOLEAN
|
|
IsUnicastIpAddrMask (
|
|
IN UINT32 Addr,
|
|
IN UINT32 Mask
|
|
)
|
|
{
|
|
UINT32 Network;
|
|
UINT32 Host;
|
|
|
|
Network = Addr & Mask;
|
|
Host = Addr & (~Mask);
|
|
DEBUG ((DEBUG_INFO, "ValidateIpAddrMask Addr %08x Mask %08x Network %08x Host %08x\n", Addr, Mask, Network, Host));
|
|
|
|
if (NET_IP_ADDR_IS_BROADCAST (Addr, Mask) ||
|
|
NET_IP_ADDR_NO_HOST_ID (Addr, Mask)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Function verifies if IPv4 address is valid.
|
|
|
|
@param[in] IpAddr Ipv4 address to verify
|
|
|
|
@retval TRUE Address is valid
|
|
@retval FALSE Adresss is invalid.
|
|
**/
|
|
BOOLEAN
|
|
IsIpv4AddressValid (
|
|
IN UINT32 IpAddr
|
|
)
|
|
{
|
|
if (NET_IP_ADDR_ALL_ZEROS (IpAddr) ||
|
|
NET_IP_ADDR_IN_ZERO_SUBNET (IpAddr) ||
|
|
NET_IP_ADDR_IN_LOOPBACK_SUBNET (IpAddr) ||
|
|
NET_IP_ADDR_IN_MULTICAST_RANGE (IpAddr) ||
|
|
NET_IP_ADDR_IN_RESERVED_RANGE (IpAddr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Function verifies if Provisioning Server Address is valid,
|
|
|
|
@param[in] ProvSrvAddr Provisioning server address to verify
|
|
|
|
@retval TRUE Address is valid
|
|
@retval FALSE Adresss is invalid.
|
|
**/
|
|
BOOLEAN
|
|
IsProvisioningServerAddressValid (
|
|
IN UINT32 ProvSrvAddr
|
|
)
|
|
{
|
|
/* this is ok (0.0.0.0) for Provisioning Server Address */
|
|
if (ProvSrvAddr == 0) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (((ProvSrvAddr & 0xFF) == 0) ||
|
|
NET_IP_ADDR_IN_ZERO_SUBNET (ProvSrvAddr) ||
|
|
NET_IP_ADDR_IN_LOOPBACK_SUBNET (ProvSrvAddr) ||
|
|
NET_IP_ADDR_IN_MULTICAST_RANGE (ProvSrvAddr) ||
|
|
NET_IP_ADDR_IN_RESERVED_RANGE (ProvSrvAddr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Callback function that parses incoming strings as IPv4 addresses or masks and verifies their correctness.
|
|
Addres has limitation for first octet: it must not be 0, 7f or greater than e0
|
|
Mask must have some highest bits set, then remaining bits all clear. Zeroes and ones must not be interleaved
|
|
Also, addr:mask combination must not produce broadcast address (unmasked bits of addr == all zeroes or all ones)
|
|
If addr / mask is invalid by itself it will be immediately rejected. Invalid addr:mask combination will only
|
|
cause a warning to appear
|
|
|
|
@param[in] Str String Token to verify
|
|
@param[in] QuestionId Key Value
|
|
|
|
@retval EFI_SUCCESS Input has been validated.
|
|
@retval EFI_UNSUPPORTED Incorrect input or string not found in HII database.
|
|
**/
|
|
EFI_STATUS
|
|
Ipv4Callback (
|
|
IN EFI_STRING_ID Str,
|
|
IN EFI_QUESTION_ID QuestionId
|
|
)
|
|
{
|
|
CHAR16 *UniStr;
|
|
UINT32 Error;
|
|
UINT32 Ip;
|
|
CHAR16 OtherString[17];
|
|
UINT32 Addr;
|
|
UINT32 Mask;
|
|
|
|
ZeroMem (OtherString, sizeof (OtherString));
|
|
|
|
UniStr = NULL;
|
|
|
|
DEBUG ((DEBUG_INFO, "Ipv4Callback, 0x%X\n", QuestionId));
|
|
if (Str != 0) {
|
|
UniStr = HiiGetString (mMebxHiiHandle, Str, NULL);
|
|
}
|
|
if (UniStr == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
Ip = Ipv4UnicodeToInteger (UniStr, &Error);
|
|
FreePool (UniStr);
|
|
if (QuestionId == KEY_IPV4MASKADDR) {
|
|
if (!IsValidIpMask (Ip)) {
|
|
Error = BAD_IP_MASK;
|
|
}
|
|
}
|
|
if (QuestionId == KEY_IPV4ADDR || QuestionId == KEY_IPV4GATEWAYADDR ||
|
|
QuestionId == KEY_IPV4PREFDNSADDR || QuestionId == KEY_IPV4ALTDNSADDR) {
|
|
if (!IsIpv4AddressValid (Ip)) {
|
|
Error = BAD_IP_ADDR;
|
|
}
|
|
}
|
|
|
|
SetVariableInBrowser (&Error, FLAG_OFFSET (ShowError) ,1);
|
|
DEBUG ((DEBUG_INFO, "CheckResult = %x\n", Error));
|
|
if (Error != INPUT_OK) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (QuestionId == KEY_IPV4ADDR || QuestionId == KEY_IPV4MASKADDR) {
|
|
if (QuestionId == KEY_IPV4ADDR) {
|
|
Addr = Ip;
|
|
GetVariableFromBrowser (FLAG_OFFSET (Ipv4MaskAddr), 32, &OtherString);
|
|
Mask = Ipv4UnicodeToInteger (OtherString, &Error);
|
|
} else {
|
|
Mask = Ip;
|
|
GetVariableFromBrowser (FLAG_OFFSET (Ipv4Addr), 32, &OtherString);
|
|
Addr = Ipv4UnicodeToInteger (OtherString, &Error);
|
|
}
|
|
ASSERT (Error == 0);
|
|
if (!IsUnicastIpAddrMask (Addr, Mask)) {
|
|
Error = BAD_IP_ADDR_MASK_COMBO;
|
|
}
|
|
|
|
SetVariableInBrowser (&Error, FLAG_OFFSET (AddrMaskInvalid), 4);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Checks if provided string is a valid hostname. If not, sets ShowError variable to indicate
|
|
the kind of problem found in string.
|
|
|
|
@param[in] Str String Token to verify
|
|
|
|
@retval EFI_SUCCESS Input has been validated.
|
|
@retval EFI_UNSUPPORTED Incorrect input or string not found in HII database.
|
|
**/
|
|
EFI_STATUS
|
|
FqdnCallback (
|
|
IN EFI_STRING_ID Str
|
|
)
|
|
{
|
|
CHAR8 Name[256];
|
|
CHAR16 *UniStr;
|
|
UINT32 CheckResult;
|
|
|
|
UniStr = NULL;
|
|
|
|
ZeroMem (Name, sizeof (Name));
|
|
DEBUG ((DEBUG_INFO, "FqdnCallback\n"));
|
|
if (Str != 0) {
|
|
UniStr = HiiGetString (mMebxHiiHandle, Str, NULL);
|
|
}
|
|
if (UniStr == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
UnicodeStrToAsciiStrS (UniStr, Name, sizeof (Name));
|
|
FreePool (UniStr);
|
|
CheckResult = ValidateHostDomainName (Name);
|
|
SetVariableInBrowser (&CheckResult, FLAG_OFFSET (ShowError) ,1);
|
|
DEBUG ((DEBUG_INFO, "CheckResult = %x\n", CheckResult));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Checks if provided string is a valid server address. If not, sets ShowError variable to indicate
|
|
the kind of problem found in string.
|
|
|
|
@param[in] Str String Token to verify
|
|
|
|
@retval EFI_SUCCESS Input has been validated.
|
|
@retval EFI_UNSUPPORTED Incorrect input or string not found in HII database.
|
|
**/
|
|
EFI_STATUS
|
|
ProvServerAddressCallback (
|
|
IN EFI_STRING_ID Str
|
|
)
|
|
{
|
|
CHAR8 Name[256];
|
|
CHAR16 *UniStr;
|
|
UINT32 CheckResult;
|
|
RETURN_STATUS Status;
|
|
IPv4_ADDRESS Ipv4;
|
|
IPv6_ADDRESS Ipv6;
|
|
UINT8 Prefix;
|
|
UINT32 Ipv4Int;
|
|
|
|
UniStr = NULL;
|
|
Prefix = 0;
|
|
ZeroMem (&Ipv6, sizeof (Ipv6));
|
|
ZeroMem (&Ipv4, sizeof (Ipv4));
|
|
ZeroMem (Name, sizeof (Name));
|
|
|
|
DEBUG ((DEBUG_INFO, "[MEBx] %a - start\n", __FUNCTION__));
|
|
if (Str != 0) {
|
|
UniStr = HiiGetString (mMebxHiiHandle, Str, NULL);
|
|
}
|
|
if (UniStr == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
UnicodeStrToAsciiStrS (UniStr, Name, sizeof (Name));
|
|
|
|
Ipv4Int = Ipv4UnicodeToInteger (UniStr, &CheckResult);
|
|
FreePool (UniStr);
|
|
if (CheckResult == INPUT_OK) {
|
|
if (!IsProvisioningServerAddressValid (Ipv4Int)) {
|
|
CheckResult = BAD_IP_ADDR;
|
|
}
|
|
SetVariableInBrowser (&CheckResult, FLAG_OFFSET (ShowError) ,1);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
Status = AsciiStrToIpv6Address (Name, NULL, &Ipv6, &Prefix);
|
|
CheckResult = RETURN_ERROR (Status) || (Prefix != MAX_UINT8);
|
|
if (CheckResult == INPUT_OK) {
|
|
SetVariableInBrowser (&CheckResult, FLAG_OFFSET (ShowError) ,1);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
CheckResult = ValidateHostDomainName (Name);
|
|
if (CheckResult == INPUT_OK) {
|
|
SetVariableInBrowser (&CheckResult, FLAG_OFFSET (ShowError) ,1);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
CheckResult = 1;
|
|
SetVariableInBrowser (&CheckResult, FLAG_OFFSET (ShowError) ,1);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
Callback funtion to be executed on ReadyToBoot event.
|
|
|
|
@param[in] Event A pointer to the Event that triggered the callback.
|
|
@param[in] Context A pointer to private data registered with the callback function.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
MebxExit (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
MebxSetMebxState (AmtMebxStateExit);
|
|
gBS->CloseEvent (Event);
|
|
}
|
|
|
|
/**
|
|
Callback for Login and Change password setup items.
|
|
It follows the logic explained in UEFI specification 2.6, paragraph 31.3.8.3.54, with certain exceptions.
|
|
According to that logic, here are the meanings of return codes from this function:
|
|
EFI_SUCCESS: user provided correct current password, browser should ask for new password
|
|
EFI_UNSUPPORTED: unercoverable error
|
|
EFI_NOT_READY: current password was incorrect
|
|
EFI_ABORTED (or any error different that the 2 above): current password was correct and browser should not ask for password change
|
|
|
|
There is a login attempt counter inside CSME. After 3 failed attempts it is impossible to login and computer must be reset.
|
|
Whenever user interacts with Password item, browser first calls this callback with empty password. Such request is not sent to CSME
|
|
to conserve the counter. Then browser calls this callback with password provided by user. If callback determines that password change
|
|
is necassary (because it was called from Change password menu item or because CSME password is still the default) then it returns
|
|
EFI_SUCCESS which indicates to browser that user should be asked for new password. In that case the current password is temporarily
|
|
stored in a global variable, because it will be used when browser calls this function again with new password.
|
|
|
|
@param[in] Str StringID where password is provided from browser. 0 if user provided invalid input
|
|
@param[in] ChangePwd If TRUE, it means user wants to change password rather than log in
|
|
|
|
@retval EFI_SUCCESS User provided correct current password, browser should ask for new password
|
|
@retval EFI_UNSUPPORTED Unhandled error
|
|
@retval EFI_NOT_READY Current password was incorrect
|
|
@retval Others Current password was correct and browser should not ask for password change
|
|
**/
|
|
EFI_STATUS
|
|
PasswordCallback (
|
|
IN EFI_STRING_ID Str,
|
|
IN BOOLEAN ChangePwd
|
|
)
|
|
{
|
|
static CHAR8 sOldPwd[MAX_PASSWORD_SIZE_TERMINATED] = {0};
|
|
static BOOLEAN sChangingPwd = FALSE;
|
|
EFI_STATUS Status;
|
|
CHAR8 Password[MAX_PASSWORD_SIZE_TERMINATED];
|
|
CHAR16 *UniStr;
|
|
BOOLEAN AttemptsExceeded;
|
|
UINT32 PasswordModified;
|
|
UINT32 PwdPolicy;
|
|
|
|
DEBUG ((DEBUG_INFO, "%a (%d)\n", __FUNCTION__, sChangingPwd));
|
|
UniStr = NULL;
|
|
|
|
if (Str != 0) {
|
|
UniStr = HiiGetString (mMebxHiiHandle, Str, NULL);
|
|
HiiSetString (mMebxHiiHandle, Str, L"", NULL);
|
|
}
|
|
if (UniStr == NULL) {
|
|
sChangingPwd = FALSE;
|
|
ZeroMem (sOldPwd, MAX_PASSWORD_SIZE_TERMINATED);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
Status = UnicodeStrToAsciiStrS (UniStr, Password, sizeof (Password));
|
|
ZeroMem (UniStr, StrSize (UniStr));
|
|
FreePool (UniStr);
|
|
if (EFI_ERROR (Status)) {
|
|
sChangingPwd = FALSE;
|
|
ZeroMem (sOldPwd, MAX_PASSWORD_SIZE_TERMINATED);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (!sChangingPwd) {
|
|
// attempt to login using provided password; skip it when the password is empty, to prevent exhausting the 3 attempts counter
|
|
AttemptsExceeded = FALSE;
|
|
if (AsciiStrLen (Password) != 0) {
|
|
Status = HeciValidateMebxPassword ((UINT8) (AsciiStrLen (Password)), (UINT8 *) &Password, &AttemptsExceeded);
|
|
} else {
|
|
Status = EFI_NOT_READY;
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
ZeroMem (Password, MAX_PASSWORD_SIZE_TERMINATED);
|
|
if (AttemptsExceeded) {
|
|
SetExposureFlag (FLAG_OFFSET (GlobalExposure), SHOW_PWD_EXCEEDED); // hide password prompt and instead show text that attempts were exceeded
|
|
ScheduleGlobalReset ();
|
|
return EFI_ABORTED;
|
|
}
|
|
return EFI_NOT_READY;
|
|
} else {
|
|
|
|
// we're correctly logged in now
|
|
gMebxConfiguration.GlobalExposure = SHOW_EVERYTHING;
|
|
SetExposureFlag (FLAG_OFFSET (GlobalExposure), SHOW_EVERYTHING);
|
|
if (gMebxConfiguration.PwdPolicy == 3) {
|
|
if (gMebxConfiguration.AmtState == AmtEnabled) {
|
|
MebxGetMebxPwdPolicy (&PwdPolicy);
|
|
gMebxConfiguration.PwdPolicy = (UINT8)PwdPolicy;
|
|
SetExposureFlag (FLAG_OFFSET (PwdPolicy), (UINT8)PwdPolicy);
|
|
}
|
|
}
|
|
}
|
|
// enforce pwd change if user asked for it or if the default password is still in use
|
|
Status = HeciIsMebxPasswordModified (&PasswordModified);
|
|
if (ChangePwd || !PasswordModified) {
|
|
sChangingPwd = TRUE;
|
|
CopyMem (sOldPwd, Password, AsciiStrLen (Password));
|
|
ZeroMem (Password, MAX_PASSWORD_SIZE_TERMINATED);
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
ZeroMem (Password, MAX_PASSWORD_SIZE_TERMINATED);
|
|
return EFI_ABORTED;
|
|
}
|
|
} else {
|
|
SetExposureFlag (FLAG_OFFSET (ShowError), INPUT_OK);
|
|
Status = HeciModifyMebxPassword ((UINT8) (AsciiStrLen (sOldPwd)), (UINT8 *) &sOldPwd, (UINT8) (AsciiStrLen ((CHAR8*)&Password)), (UINT8*)&Password);
|
|
sChangingPwd = FALSE;
|
|
ZeroMem (sOldPwd, MAX_PASSWORD_SIZE_TERMINATED);
|
|
ZeroMem (Password, MAX_PASSWORD_SIZE_TERMINATED);
|
|
if (Status != 0) {
|
|
SetExposureFlag (FLAG_OFFSET (ShowError), BAD_NEW_PWD);
|
|
// if default password has not been modified it means we are on login screen. Show login only.
|
|
if (!ChangePwd) {
|
|
SetExposureFlag (FLAG_OFFSET (GlobalExposure), SHOW_LOGIN);
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Checks whether the given FormId is main MEBx menu or direct submenu of MEBx main menu.
|
|
This is required in order correctly determine if MebxSetMebxState should be sent or not.
|
|
Whenever user is in MEBx, MebxSetMebxState (AmtMebxStateEnter) should be the last issued AMTHI command of
|
|
this type. The knowledge of direct submenus is needed, because EFI_BROWSER_ACTION_FORM_CLOSE is executed
|
|
whenever user exits the menu or enters a submenu, causing to send MebxSetMebxState (AmtMebxStateExit) command.
|
|
We need to resend MebxSetMebxState (AmtMebxStateEnter) to be sure that KVM is not supported at this time.
|
|
|
|
@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.
|
|
|
|
@retval TRUE User has entered MEBx main menu or direct submenu.
|
|
@retval FALSE User has entered any other menu.
|
|
**/
|
|
BOOLEAN
|
|
IsMebxFormId (
|
|
IN EFI_QUESTION_ID QuestionId
|
|
)
|
|
{
|
|
switch (QuestionId) {
|
|
case FORM_ID_MEBX:
|
|
case FORM_ID_AMT:
|
|
case FORM_ID_OEM_DEBUG:
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
See UEFI spec for the general meaning of Callback function.
|
|
This function mostly just calls other, specific callback functions depending on question ID
|
|
For Remote Assistance it also toggles between two strings to make impression that code didn't hang yet while
|
|
it waits for remote connection
|
|
|
|
@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.
|
|
@param[in] Type The type of value for the question.
|
|
@param[in] 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
|
|
DriverCallback (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN EFI_BROWSER_ACTION Action,
|
|
IN EFI_QUESTION_ID QuestionId,
|
|
IN UINT8 Type,
|
|
IN EFI_IFR_TYPE_VALUE *Value,
|
|
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_EVENT Event;
|
|
UINT8 CheckResult;
|
|
static UINT8 CurrentMebxState = MEBX_STATE_UNDEFINED;
|
|
|
|
if (Action == EFI_BROWSER_ACTION_FORM_OPEN && IsMebxFormId (QuestionId)) {
|
|
//
|
|
// When user opens MEBx submenu, remote admin shouldn't be able to connect to it through KVM.
|
|
// Create a ReadyToBootEvent to be sure that Exit State is sent to CSME before OS.
|
|
//
|
|
if (CurrentMebxState == MEBX_STATE_UNDEFINED) {
|
|
Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, MebxExit, NULL, &gMePlatformReadyToBootGuid, &Event);
|
|
}
|
|
|
|
if (CurrentMebxState != AmtMebxStateEnter) {
|
|
Status = MebxSetMebxState (AmtMebxStateEnter);
|
|
if (EFI_ERROR (Status) && (Status == EFI_ALREADY_STARTED)) {
|
|
MebxDisplayError (KvmActiveSessionMsg);
|
|
SetExposureFlag (FLAG_OFFSET (GlobalExposure), SHOW_REDIR_ACTIVE);
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
CurrentMebxState = AmtMebxStateEnter;
|
|
}
|
|
|
|
} else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE && QuestionId == FORM_ID_MEBX) {
|
|
//
|
|
// When user exits MEBx submenu, remote admin should be able to connect to BIOS setup through KVM
|
|
//
|
|
MebxSetMebxState (AmtMebxStateExit);
|
|
CurrentMebxState = AmtMebxStateExit;
|
|
}
|
|
|
|
if ((Action == EFI_BROWSER_ACTION_CHANGING) && (QuestionId == KEY_MEPWD || QuestionId == KEY_CHANGEMEPWD)) {
|
|
return PasswordCallback (Value->string, (QuestionId == KEY_CHANGEMEPWD));
|
|
}
|
|
|
|
if (QuestionId == KEY_HOSTDOMAINNAME || QuestionId == KEY_PKIDNSSUFFIX) {
|
|
if (Action == EFI_BROWSER_ACTION_CHANGING) {
|
|
return FqdnCallback (Value->string);
|
|
}
|
|
}
|
|
|
|
if (QuestionId == KEY_PROVSERVERFQDNADDR && Action == EFI_BROWSER_ACTION_CHANGING) {
|
|
return ProvServerAddressCallback (Value->string);
|
|
}
|
|
if (QuestionId == KEY_STARTCONFIG && Action == EFI_BROWSER_ACTION_CHANGING) {
|
|
Status = MebxActivateRemoteConfiguration (&gMebxConfiguration.ProvisioningState);
|
|
CheckResult = (UINT8) EFI_ERROR (Status);
|
|
SetVariableInBrowser (&CheckResult, FLAG_OFFSET (ShowError) ,1);
|
|
SET_IN_BROWSER (gMebxConfiguration, ProvisioningState);
|
|
}
|
|
if (QuestionId == KEY_HALTCONFIG && Action == EFI_BROWSER_ACTION_CHANGING) {
|
|
Status = MebxStopRemoteConfiguration (&gMebxConfiguration.ProvisioningState);
|
|
CheckResult = (UINT8) EFI_ERROR (Status);
|
|
SetVariableInBrowser (&CheckResult, FLAG_OFFSET (ShowError) ,1);
|
|
SET_IN_BROWSER (gMebxConfiguration, ProvisioningState);
|
|
}
|
|
|
|
if ((QuestionId == KEY_IPV4ADDR) ||
|
|
(QuestionId == KEY_IPV4MASKADDR) ||
|
|
(QuestionId == KEY_IPV4GATEWAYADDR) ||
|
|
(QuestionId == KEY_IPV4PREFDNSADDR) ||
|
|
(QuestionId == KEY_IPV4ALTDNSADDR)) {
|
|
if (Action == EFI_BROWSER_ACTION_CHANGING) {
|
|
return Ipv4Callback (Value->string, QuestionId);
|
|
}
|
|
}
|
|
if (Action >= EFI_BROWSER_ACTION_DEFAULT_STANDARD) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
See UEFI spec for the general meaning of ExtractConfig function.
|
|
MEBx is unusual in that it doesn't store configuration entered by user in EFI flash variables.
|
|
Instead, all(*) config is retrieved from CSME firmware using HECI messages.
|
|
"All" actually means all except Password Policy which can't be read unless user is logged in,
|
|
which is not the case at the time ExtractCondig is executed. Instead Password Policy will be retrieved inside PasswordCallback.
|
|
|
|
@param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param[in] Request A null-terminated Unicode string in <ConfigRequest> 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 is filled with the requested values.
|
|
@retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
|
|
@retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
|
|
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ExtractConfig (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN CONST EFI_STRING Request,
|
|
OUT EFI_STRING *Progress,
|
|
OUT EFI_STRING *Results
|
|
)
|
|
{
|
|
if ((NULL == This) || (NULL == Progress) || (NULL == Results)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "MEBx Setup Extract Config:\n"));
|
|
MebxGetInfo (&gMebxConfiguration);
|
|
ShowConfig (&gMebxConfiguration);
|
|
|
|
// can't read PwdPolicy here, AmthiCfgGetMebxPwdChangePolicy message only works after login
|
|
return mHiiConfigRouting->BlockToConfig (
|
|
mHiiConfigRouting,
|
|
Request,
|
|
(UINT8 *) &gMebxConfiguration,
|
|
sizeof (MEBX_CONFIGURATION),
|
|
Results,
|
|
Progress
|
|
);
|
|
|
|
}
|
|
|
|
/**
|
|
Promote next platform reset to Global type. Required after changing certain settings in MEBX.
|
|
|
|
@param[in] ResetType UEFI defined reset type.
|
|
@param[in] ResetStatus The status code for the reset.
|
|
@param[in] DataSize The size of ResetData in bytes.
|
|
@param[in] ResetData Optional element used to introduce a platform specific reset.
|
|
The exact type of the reset is defined by the EFI_GUID that follows
|
|
the Null-terminated Unicode string.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ResetHook (
|
|
IN EFI_RESET_TYPE ResetType,
|
|
IN EFI_STATUS ResetStatus,
|
|
IN UINTN DataSize,
|
|
IN VOID *ResetData OPTIONAL
|
|
)
|
|
{
|
|
PCH_RESET_DATA NewResetData;
|
|
|
|
if (ResetType == EfiResetPlatformSpecific) {
|
|
return;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "MEBx requires Global Reset\n"));
|
|
DataSize = sizeof (PCH_RESET_DATA);
|
|
CopyMem (&NewResetData.Guid, &gPchGlobalResetGuid, sizeof (EFI_GUID));
|
|
StrCpyS (NewResetData.Description, PCH_RESET_DATA_STRING_MAX_LENGTH, PCH_PLATFORM_SPECIFIC_RESET_STRING);
|
|
|
|
gRT->ResetSystem (EfiResetPlatformSpecific, EFI_SUCCESS, DataSize, &NewResetData);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Promote next platform reset to Global type. Required after changing certain settings in MEBX.
|
|
**/
|
|
VOID
|
|
ScheduleGlobalReset (
|
|
VOID
|
|
)
|
|
{
|
|
EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PROTOCOL *ResetFilter;
|
|
static BOOLEAN ResetAlreadyScheduled = FALSE;
|
|
EFI_STATUS Status;
|
|
|
|
if (ResetAlreadyScheduled) {
|
|
return;
|
|
}
|
|
ResetAlreadyScheduled = TRUE;
|
|
|
|
Status = gBS->LocateProtocol (&gEdkiiPlatformSpecificResetFilterProtocolGuid, NULL, (VOID **) &ResetFilter);
|
|
if (!EFI_ERROR (Status)) {
|
|
ResetFilter->RegisterResetNotify (ResetFilter, ResetHook);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Address of provisioning server is provided by user as unicode string.
|
|
This function checks if it was provided as IPv4 addr, IPv6 addr or host name.
|
|
IPvN vs host address are sent in different fields of the same
|
|
AMTHI message, so a decision must be taken which type of address it is and where to put it
|
|
|
|
@param[in] Address Configuration Server Address
|
|
@param[in] Port Configuration Server Port Value
|
|
|
|
@retval EFI_SUCCESS Command succeeded
|
|
@retval EFI_INVALID_PARAMETER NULL parameter
|
|
@retval EFI_UNSUPPORTED Current ME mode doesn't support this function
|
|
@retval EFI_DEVICE_ERROR HECI Device error, command aborts abnormally
|
|
@retval EFI_TIMEOUT HECI does not return the buffer before timeout
|
|
@retval EFI_BUFFER_TOO_SMALL Message Buffer is too small for the Acknowledge
|
|
**/
|
|
EFI_STATUS
|
|
UpdateProvisioningServer (
|
|
IN CHAR16 *Address,
|
|
IN UINT16 Port
|
|
)
|
|
{
|
|
FQDN_ANSI_STRING Fqdn;
|
|
UINT8 IpAddress[CFG_IPV6_ADDR_LEN_MAX + 1];
|
|
UINT32 Error;
|
|
EFI_STATUS Status;
|
|
IPv6_ADDRESS Ipv6;
|
|
UINT8 Prefix;
|
|
|
|
if (Address == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Prefix = 0;
|
|
Error = 0;
|
|
|
|
Ipv4UnicodeToInteger (Address, &Error);
|
|
if (Error) {
|
|
Status = StrToIpv6Address (Address, NULL, &Ipv6, &Prefix);
|
|
Error = EFI_ERROR (Status) || (Prefix != MAX_UINT8);
|
|
}
|
|
// if Address could be converted to either IPv4 or IPv6 then send it in IP field of AMTHI message
|
|
if (!Error) {
|
|
UnicodeStrToAsciiStrS (Address, (CHAR8 *) &IpAddress, sizeof (IpAddress));
|
|
ZeroMem (&Fqdn, sizeof (Fqdn));
|
|
} else {
|
|
UnicodeStrToAsciiStrS (Address, (CHAR8 *) &Fqdn.Buffer, sizeof (Fqdn.Buffer));
|
|
Fqdn.Length = (UINT16) AsciiStrLen ((CHAR8 *) &Fqdn.Buffer);
|
|
ZeroMem (IpAddress, CFG_IPV6_ADDR_LEN_MAX);
|
|
CopyMem (IpAddress, "0.0.0.0", 8);
|
|
}
|
|
return MebxSetConfigServerData (Port, IpAddress, &Fqdn);
|
|
}
|
|
|
|
/**
|
|
Update current IPV4 TCPIP Parameters.
|
|
|
|
The function adjusts input parameters to format supported by HECI message.
|
|
|
|
@param[in] DhcpMode Mode of AMT DHCP operation
|
|
@param[in] LocalAddr Local IP address that the AMT device uses
|
|
@param[in] SubnetMask Mask for the local subnet
|
|
@param[in] GatewayAddr IP address of the default gateway that the AMT device uses
|
|
@param[in] PriDnsAddr IP Address of the Primary DNS
|
|
@param[in] SecDnsAddr IP Address of the Secondary DNS
|
|
|
|
@retval EFI_SUCCESS Command succeeded
|
|
@retval EFI_INVALID_PARAMETER NULL parameter
|
|
@retval EFI_UNSUPPORTED Current ME mode doesn't support this function
|
|
@retval EFI_DEVICE_ERROR HECI Device error, command aborts abnormally
|
|
@retval EFI_TIMEOUT HECI does not return the buffer before timeout
|
|
@retval EFI_BUFFER_TOO_SMALL Message Buffer is too small for the Acknowledge
|
|
**/
|
|
EFI_STATUS
|
|
UpdateIpv4Params (
|
|
IN UINT8 DhcpMode,
|
|
IN CHAR16 *LocalAddr,
|
|
IN CHAR16 *SubnetMask,
|
|
IN CHAR16 *GatewayAddr,
|
|
IN CHAR16 *PriDnsAddr,
|
|
IN CHAR16 *SecDnsAddr
|
|
)
|
|
{
|
|
IMB_TCPIP_PARAMS NewIpv4Cfg;
|
|
UINT32 Error;
|
|
|
|
if (LocalAddr == NULL || SubnetMask == NULL || GatewayAddr == NULL || PriDnsAddr == NULL || SecDnsAddr == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
NewIpv4Cfg.DhcpMode = DhcpMode;
|
|
NewIpv4Cfg.LocalAddr = Ipv4UnicodeToInteger (LocalAddr, &Error);
|
|
NewIpv4Cfg.SubnetMask = Ipv4UnicodeToInteger (SubnetMask, &Error);
|
|
NewIpv4Cfg.GatewayAddr = Ipv4UnicodeToInteger (GatewayAddr, &Error);
|
|
NewIpv4Cfg.PriDnsAddr = Ipv4UnicodeToInteger (PriDnsAddr, &Error);
|
|
NewIpv4Cfg.SecDnsAddr = Ipv4UnicodeToInteger (SecDnsAddr, &Error);
|
|
|
|
// Domain name is always set to 0s
|
|
NewIpv4Cfg.DomainName.Length = 0;
|
|
ZeroMem (&NewIpv4Cfg.DomainName.Buffer, MAX_ASCII_STRING);
|
|
|
|
return MebxSetIpv4Params (&NewIpv4Cfg);
|
|
}
|
|
|
|
/**
|
|
Attempts to find given char inside string. If found, returns index of this char inside string.
|
|
Otherwise, returns index that equals Length or points to null-terminator, whatever comes first
|
|
|
|
@param[in] Value ASCII Value of the char to be found
|
|
@param[in] String Pointer to the investigated string
|
|
@param[in] Length Max string length
|
|
|
|
@retval Position Index of the found character
|
|
**/
|
|
UINT32
|
|
FindChar (
|
|
IN CHAR8 Value,
|
|
IN CHAR8 *String,
|
|
IN UINT32 Length
|
|
)
|
|
{
|
|
UINT32 Position;
|
|
Position = 0;
|
|
while (Position < Length && String[Position] != '\0' && String[Position] != Value) {
|
|
Position++;
|
|
}
|
|
return Position;
|
|
}
|
|
|
|
/**
|
|
Update current FQDN Data.
|
|
|
|
@param[in] FqdnType Whether the domain name is shared with the Host or dedicated to ME
|
|
@param[in] DynamicDnsUpdate Whether the Dynamic DNS Update Client in FW is enabled or not
|
|
@param[in] UpdateInterval Defines the interval at which the FW DDNS Update client will send
|
|
periodic updates for all the RRs registered by FW
|
|
@param[in] Ttl The TTL value in seconds for RRs registered by FW
|
|
@param[in] HostDomainName Host Domain name
|
|
|
|
@retval EFI_SUCCESS Command succeeded
|
|
@retval EFI_INVALID_PARAMETER NULL parameter
|
|
@retval EFI_UNSUPPORTED Current ME mode doesn't support this function
|
|
@retval EFI_DEVICE_ERROR HECI Device error, command aborts abnormally
|
|
@retval EFI_TIMEOUT HECI does not return the buffer before timeout
|
|
@retval EFI_BUFFER_TOO_SMALL Message Buffer is too small for the Acknowledge
|
|
**/
|
|
EFI_STATUS
|
|
UpdateFqdn (
|
|
IN UINT8 FqdnType,
|
|
IN UINT8 DynamicDnsUpdate,
|
|
IN UINT32 UpdateInterval,
|
|
IN UINT32 Ttl,
|
|
IN CHAR16 *HostDomainName
|
|
)
|
|
{
|
|
FQDN_DATA SendMe;
|
|
|
|
if (HostDomainName == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ZeroMem (&SendMe, sizeof (SendMe));
|
|
SendMe.SharedFqdn = FqdnType;
|
|
SendMe.DdnsUpdateEnabled = DynamicDnsUpdate;
|
|
SendMe.DdnsPeriodicUpdateInterval = UpdateInterval;
|
|
SendMe.DdnsTtl = Ttl;
|
|
SendMe.Fqdn.Length = (UINT16)StrLen (HostDomainName);
|
|
UnicodeStrToAsciiStrS (HostDomainName, (CHAR8 *) &SendMe.Fqdn.Buffer, MAX_STRING_LENGTH_FQDN);
|
|
SendMe.HostNameLength = FindChar ('.', (CHAR8 *) &SendMe.Fqdn.Buffer, SendMe.Fqdn.Length);
|
|
|
|
return MebxSetFqdn (&SendMe);
|
|
}
|
|
|
|
/**
|
|
Update current PKI FQDN DNS Suffix.
|
|
|
|
@attention Function is not allowed in POST_PROVISION State
|
|
|
|
@param[in] NewPkiDns New Fqdn Pki Dns suffix
|
|
|
|
@retval EFI_SUCCESS Command succeeded
|
|
@retval EFI_INVALID_PARAMETER NULL parameter
|
|
@retval EFI_UNSUPPORTED Current ME mode doesn't support this function
|
|
@retval EFI_DEVICE_ERROR HECI Device error, command aborts abnormally
|
|
@retval EFI_TIMEOUT HECI does not return the buffer before timeout
|
|
@retval EFI_BUFFER_TOO_SMALL Message Buffer is too small for the Acknowledge
|
|
**/
|
|
EFI_STATUS
|
|
UpdatePkiFqdnSuffix (
|
|
IN CHAR16 *PkiDnsSuffix
|
|
)
|
|
{
|
|
FQDN_SUFFIX_ANSI_STRING Fqdn;
|
|
|
|
if (PkiDnsSuffix == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ZeroMem (&Fqdn, sizeof (Fqdn));
|
|
Fqdn.Length = (UINT16)StrLen (PkiDnsSuffix);
|
|
UnicodeStrToAsciiStrS (PkiDnsSuffix, (CHAR8 *) &Fqdn.Buffer, MAX_STRING_LENGTH_FQDN_SUFFIX);
|
|
|
|
return MebxSetPkiFqdnSuffix (&Fqdn);
|
|
}
|
|
|
|
/**
|
|
See UEFI spec for the general meaning of RouteConfig function.
|
|
MEBx is unusual in that it doesn't store configuration entered by user in EFI flash variables.
|
|
Instead, all config is passed to CSME firmware using HECI messages.
|
|
Such messages take time, so as an optimization only those settings that did change will generate messages:
|
|
we first check delta between copy of CSME config (stored in gMebxConfiguration) and the new config coming from browser (NewCfg)
|
|
Disabling AMT prevents any other changes from being sent. Changing NetAccess resets most other settings so they must be
|
|
retrieved from CSME and updated in browser. Some settings cannot be changed unless user is logged in.
|
|
All those cases are handled in this function.
|
|
|
|
@param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param[in] Configuration A null-terminated Unicode string in <ConfigResp>
|
|
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 is processed successfully.
|
|
@retval EFI_INVALID_PARAMETER Configuration is NULL.
|
|
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this
|
|
driver.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RouteConfig (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN CONST EFI_STRING Configuration,
|
|
OUT EFI_STRING *Progress
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BufferSize;
|
|
MEBX_CONFIGURATION NewCfg;
|
|
UINT32 AmthiStatus;
|
|
BOOLEAN IsGlobalResetRequired;
|
|
UINT32 HashNumber;
|
|
|
|
DEBUG ((DEBUG_INFO, "MEBx Setup Route Config:\n"));
|
|
DEBUG ((DEBUG_INFO, "%s\n", Configuration));
|
|
|
|
if ((NULL == This) || (NULL == Progress)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
IsGlobalResetRequired = FALSE;
|
|
|
|
// Copy full buffer to make sure NewCfg uses full set of data even when Configuration string does not contain full struct
|
|
CopyMem (&NewCfg, &gMebxConfiguration, sizeof (NewCfg));
|
|
BufferSize = sizeof (MEBX_CONFIGURATION);
|
|
Status = mHiiConfigRouting->ConfigToBlock (mHiiConfigRouting, Configuration, (UINT8 *) &NewCfg, &BufferSize, Progress);
|
|
if (gMebxConfiguration.GlobalExposure != SHOW_EVERYTHING || NewCfg.GlobalExposure != SHOW_EVERYTHING) {
|
|
goto Exit;
|
|
}
|
|
//
|
|
// Compare gMebxConfiguration with NewCfg and send Heci msg for every item that's different
|
|
//
|
|
ShowConfigDiff (&gMebxConfiguration, &NewCfg);
|
|
|
|
if (NewCfg.AmtState != gMebxConfiguration.AmtState) {
|
|
Status = MebxSetAmtState (NewCfg.AmtState);
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (MeSetAmtStateApiError);
|
|
return Status;
|
|
}
|
|
IsGlobalResetRequired = TRUE;
|
|
|
|
//
|
|
// If AMT was disabled and user enables it, AMT menu will be inaccessible until reboot.
|
|
// To change this behavior, one needs to retrieve whole AMT config here.
|
|
//
|
|
NewCfg.AmtStateExposure = 0;
|
|
SetExposureFlag (FLAG_OFFSET (AmtStateExposure), 0);
|
|
goto Exit;
|
|
}
|
|
|
|
if (NewCfg.TlsPpkRemoteConfig != gMebxConfiguration.TlsPpkRemoteConfig) {
|
|
Status = MebxSetZeroTouchEnabled (NewCfg.TlsPpkRemoteConfig);
|
|
if (NewCfg.TlsPpkRemoteConfig == 0 && NewCfg.ProvisioningState == 1) {
|
|
// partial unprovisioning is a side effect of disabling ZTC during IN provisioning state
|
|
NewCfg.NetAccess = MAX (NewCfg.NetAccess, 2);
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiSetZtcApiError);
|
|
}
|
|
}
|
|
if (StrCmp (NewCfg.PkiDnsSuffix, gMebxConfiguration.PkiDnsSuffix)) {
|
|
Status = UpdatePkiFqdnSuffix (NewCfg.PkiDnsSuffix);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiSetPkiFqdnSuffixApiError);
|
|
}
|
|
}
|
|
if (NewCfg.NetAccess != gMebxConfiguration.NetAccess) {
|
|
switch (NewCfg.NetAccess) {
|
|
case 0:
|
|
MebxCompleteConfigurationRequest (&AmthiStatus);
|
|
break;
|
|
case 1:
|
|
ASSERT (FALSE);
|
|
break;
|
|
case 2:
|
|
MebxPerformUnprovisioning (UnprovisionTypePartial);
|
|
break;
|
|
case 3:
|
|
MebxPerformUnprovisioning (UnprovisionTypeFull);
|
|
break;
|
|
}
|
|
Status = MebxGetProvisioningState (&NewCfg.ProvisioningState);
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiGetProvisionStateApiError);
|
|
return Status;
|
|
}
|
|
SET_IN_BROWSER (NewCfg, ProvisioningState);
|
|
if (NewCfg.NetAccess > 1) {
|
|
//get new values for all fields because they might have changed
|
|
NewCfg.NetAccess = 1;
|
|
SET_IN_BROWSER (NewCfg, NetAccess);
|
|
MebxGetInfo (&NewCfg);
|
|
SET_IN_BROWSER (NewCfg, MeOnHostSlpStates);
|
|
SET_IN_BROWSER (NewCfg, IdleTimeout);
|
|
SET_IN_BROWSER (NewCfg, PwdPolicy);
|
|
SET_IN_BROWSER (NewCfg, SolEnable);
|
|
SET_IN_BROWSER (NewCfg, StorageRedirEnable);
|
|
SET_IN_BROWSER (NewCfg, KvmEnable);
|
|
SET_IN_BROWSER (NewCfg, UserOptIn);
|
|
SET_IN_BROWSER (NewCfg, RemoteItOptInConfig);
|
|
SET_IN_BROWSER (NewCfg, HostDomainName);
|
|
SET_IN_BROWSER (NewCfg, FqdnType);
|
|
SET_IN_BROWSER (NewCfg, DynamicDnsUpdate);
|
|
SET_IN_BROWSER (NewCfg, UpdateInterval);
|
|
SET_IN_BROWSER (NewCfg, Ttl);
|
|
SET_IN_BROWSER (NewCfg, DhcpMode);
|
|
SET_IN_BROWSER (NewCfg, Ipv4Addr);
|
|
SET_IN_BROWSER (NewCfg, Ipv4MaskAddr);
|
|
SET_IN_BROWSER (NewCfg, Ipv4GatewayAddr);
|
|
SET_IN_BROWSER (NewCfg, Ipv4PrefDnsAddr);
|
|
SET_IN_BROWSER (NewCfg, Ipv4AltDnsAddr);
|
|
SET_IN_BROWSER (NewCfg, ProvServerAddr);
|
|
SET_IN_BROWSER (NewCfg, ProvServerPort);
|
|
SET_IN_BROWSER (NewCfg, TlsPpkRemoteConfig);
|
|
SET_IN_BROWSER (NewCfg, PkiDnsSuffix);
|
|
SET_IN_BROWSER (NewCfg, PrivacyLevel);
|
|
SET_IN_BROWSER (NewCfg, LanLessPlatform);
|
|
SET_IN_BROWSER (NewCfg, NumberOfPowerPkgs);
|
|
SET_IN_BROWSER (NewCfg, NoDefaultHashes);
|
|
SET_IN_BROWSER (NewCfg, HashValid);
|
|
SET_IN_BROWSER (NewCfg, Pwd);
|
|
SET_IN_BROWSER (NewCfg, MOffOverride);
|
|
SET_IN_BROWSER (NewCfg, SouthClinkState);
|
|
SET_IN_BROWSER (NewCfg, AmtStateExposure);
|
|
SET_IN_BROWSER (NewCfg, AmtSubmenuExposure);
|
|
SET_IN_BROWSER (NewCfg, KvmExposure);
|
|
SET_IN_BROWSER (NewCfg, ProvisioningState);
|
|
SET_IN_BROWSER (NewCfg, OptInConfigExposure);
|
|
SET_IN_BROWSER (NewCfg, RemoteItOptInConfigExposure);
|
|
SET_IN_BROWSER (NewCfg, GlobalExposure);
|
|
SET_IN_BROWSER (NewCfg, SelectedHashType);
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if ((NewCfg.SolEnable != gMebxConfiguration.SolEnable) ||
|
|
(NewCfg.StorageRedirEnable != gMebxConfiguration.StorageRedirEnable)) {
|
|
IsGlobalResetRequired = TRUE;
|
|
Status = MebxSetSolStorageRedir (NewCfg.SolEnable, NewCfg.StorageRedirEnable);
|
|
HeciSetInvocationCode (DATA_SYNC_CONFIRMATION);
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiSetSolStorageRedirectionStateApiError);
|
|
}
|
|
}
|
|
|
|
if (NewCfg.KvmEnable != gMebxConfiguration.KvmEnable) {
|
|
IsGlobalResetRequired = TRUE;
|
|
Status = MebxSetKvmEnabled (NewCfg.KvmEnable);
|
|
HeciSetInvocationCode (DATA_SYNC_CONFIRMATION);
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiSetKvmStateApiError);
|
|
}
|
|
}
|
|
if (NewCfg.PwdPolicy != gMebxConfiguration.PwdPolicy) {
|
|
MebxSetMebxPwdPolicy (NewCfg.PwdPolicy);
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiSetPwdPolicyApiError);
|
|
}
|
|
|
|
}
|
|
if (StrCmp (NewCfg.HostDomainName, gMebxConfiguration.HostDomainName) ||
|
|
(NewCfg.FqdnType != gMebxConfiguration.FqdnType) ||
|
|
(NewCfg.DynamicDnsUpdate != gMebxConfiguration.DynamicDnsUpdate) ||
|
|
(NewCfg.UpdateInterval != gMebxConfiguration.UpdateInterval) ||
|
|
(NewCfg.Ttl != gMebxConfiguration.Ttl)) {
|
|
|
|
Status = UpdateFqdn (
|
|
NewCfg.FqdnType,
|
|
NewCfg.DynamicDnsUpdate,
|
|
NewCfg.UpdateInterval,
|
|
NewCfg.Ttl,
|
|
NewCfg.HostDomainName
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiSetFqdnApiError);
|
|
}
|
|
}
|
|
|
|
if ((NewCfg.RemoteItOptInConfig != gMebxConfiguration.RemoteItOptInConfig) ||
|
|
(NewCfg.UserOptIn != gMebxConfiguration.UserOptIn)) {
|
|
MebxSetOptInState (NewCfg.UserOptIn, (UINT32)NewCfg.RemoteItOptInConfig);
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiSetOptinStateApiError);
|
|
}
|
|
}
|
|
if (NewCfg.IdleTimeout != gMebxConfiguration.IdleTimeout) {
|
|
MebxSetIdleTimeout (NewCfg.IdleTimeout);
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiSetIdleTimeoutApiError);
|
|
}
|
|
}
|
|
|
|
if ((NewCfg.DhcpMode != gMebxConfiguration.DhcpMode) ||
|
|
StrCmp (NewCfg.Ipv4GatewayAddr, gMebxConfiguration.Ipv4GatewayAddr) ||
|
|
StrCmp (NewCfg.Ipv4Addr, gMebxConfiguration.Ipv4Addr) ||
|
|
StrCmp (NewCfg.Ipv4PrefDnsAddr, gMebxConfiguration.Ipv4PrefDnsAddr) ||
|
|
StrCmp (NewCfg.Ipv4AltDnsAddr, gMebxConfiguration.Ipv4AltDnsAddr) ||
|
|
StrCmp (NewCfg.Ipv4MaskAddr, gMebxConfiguration.Ipv4MaskAddr) ) {
|
|
|
|
Status = UpdateIpv4Params (
|
|
NewCfg.DhcpMode,
|
|
NewCfg.Ipv4Addr,
|
|
NewCfg.Ipv4MaskAddr,
|
|
NewCfg.Ipv4GatewayAddr,
|
|
NewCfg.Ipv4PrefDnsAddr,
|
|
NewCfg.Ipv4AltDnsAddr
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiSetIpv4ParamsApiError);
|
|
}
|
|
}
|
|
|
|
if (StrCmp (NewCfg.ProvServerAddr, gMebxConfiguration.ProvServerAddr) ||
|
|
NewCfg.ProvServerPort != gMebxConfiguration.ProvServerPort) {
|
|
Status = UpdateProvisioningServer (NewCfg.ProvServerAddr, NewCfg.ProvServerPort);
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiSetConfigServerApiError);
|
|
}
|
|
}
|
|
|
|
|
|
if (NewCfg.MeOnHostSlpStates != gMebxConfiguration.MeOnHostSlpStates) {
|
|
Status = MebxUpdatePowerPolicy (NewCfg.MeOnHostSlpStates);
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiPowerPolicyApiError);
|
|
}
|
|
}
|
|
|
|
if (NewCfg.MOffOverride != gMebxConfiguration.MOffOverride) {
|
|
Status = HeciSetMoffOverrideState (NewCfg.MOffOverride);
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (MeSetMoffOvrdStateApiError);
|
|
}
|
|
IsGlobalResetRequired = TRUE;
|
|
}
|
|
|
|
if (NewCfg.SouthClinkState != gMebxConfiguration.SouthClinkState) {
|
|
Status = HeciSetSouthClinkState (NewCfg.SouthClinkState);
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (MeSetSouthClinkStateApiError);
|
|
}
|
|
IsGlobalResetRequired = TRUE;
|
|
}
|
|
|
|
for (HashNumber = 0; HashNumber < MAX_HASH_ENTRIES; HashNumber++) {
|
|
if (NewCfg.CertActive[HashNumber] != gMebxConfiguration.CertActive[HashNumber]) {
|
|
Status = MebxSetCertificateHashState (&NewCfg.CertHandle[HashNumber], NewCfg.CertActive[HashNumber]);
|
|
if (EFI_ERROR (Status)) {
|
|
MebxDisplayError (AmthiSetHashStateApiError);
|
|
}
|
|
}
|
|
}
|
|
Exit:
|
|
CopyMem (&gMebxConfiguration, &NewCfg, sizeof (MEBX_CONFIGURATION));
|
|
if (IsGlobalResetRequired) {
|
|
ScheduleGlobalReset ();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
There are 2 marketing brands of AMT: "AMT" itself and "Standard Manageability".
|
|
This function adjusts brand strings that will be displayed in setup browser
|
|
**/
|
|
VOID
|
|
ReplaceBrandStrings (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STRING Temp;
|
|
|
|
Temp = HiiGetString (mMebxHiiHandle, STRING_TOKEN (STR_SUBMENU_STD_MANAGEABILITY), NULL);
|
|
HiiSetString (mMebxHiiHandle, STRING_TOKEN (STR_SUBMENU_AMT), Temp, NULL);
|
|
FreePool (Temp);
|
|
Temp = HiiGetString (mMebxHiiHandle, STRING_TOKEN (STR_STD_MANAGEABILITY_DISABLED), NULL);
|
|
HiiSetString (mMebxHiiHandle, STRING_TOKEN (STR_AMT_DISABLED), Temp, NULL);
|
|
FreePool (Temp);
|
|
Temp = HiiGetString (mMebxHiiHandle, STRING_TOKEN (STR_OPTION_STD_MANAGEABILITY_GLOBAL_STATE), NULL);
|
|
HiiSetString (mMebxHiiHandle, STRING_TOKEN (STR_OPTION_AMT_GLOBAL_STATE), Temp, NULL);
|
|
FreePool (Temp);
|
|
}
|
|
|
|
/**
|
|
This function integrates MEBx with BIOS setup browser by publishing MEBx's formset
|
|
and HII config access protocol.
|
|
|
|
@param[in] PlatformBrand Platform Brand:
|
|
@see PLATFORM_BRAND
|
|
|
|
@retval EFI_SUCCESS Successfully published MEBx setup data
|
|
@retval Others Error while publishing MEBx setup data
|
|
**/
|
|
EFI_STATUS
|
|
MebxSetupInit (
|
|
IN UINT32 PlatformBrand
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE DriverHandle;
|
|
|
|
DEBUG ((DEBUG_INFO, "%a start\n", __FUNCTION__));
|
|
|
|
gMebxConfigAccess.ExtractConfig = ExtractConfig;
|
|
gMebxConfigAccess.RouteConfig = RouteConfig;
|
|
gMebxConfigAccess.Callback = DriverCallback;
|
|
|
|
//
|
|
// Locate required Hii protocols
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiHiiConfigRoutingProtocolGuid,
|
|
NULL,
|
|
(VOID **) &mHiiConfigRouting
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Install Device Path Protocol and Config Access protocol to driver handle.
|
|
//
|
|
DriverHandle = NULL;
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&DriverHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&mHiiVendorDevicePath,
|
|
&gEfiHiiConfigAccessProtocolGuid,
|
|
&gMebxConfigAccess,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "%a Publishing HII Data\n", __FUNCTION__));
|
|
|
|
mMebxHiiHandle = HiiAddPackages (
|
|
&gMebxFormSetGuid,
|
|
DriverHandle,
|
|
MebxSetupStrings,
|
|
MebxSetupVfrBin,
|
|
NULL
|
|
);
|
|
ASSERT (mMebxHiiHandle != NULL);
|
|
if (mMebxHiiHandle == NULL) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (PlatformBrand == IntelStandardManageabilityBrand) {
|
|
ReplaceBrandStrings ();
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "%a end\n", __FUNCTION__));
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Driver's entry point. Checks if MEBx is supported and publishes
|
|
setup formset into setup browser.
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS MEBx driver initialized successfully
|
|
@retval EFI_UNSUPPORTED Feature is not supported by the FW
|
|
@retval Others MEBx driver initialization failed
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
MebxSetupEntry (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE* SystemTable
|
|
)
|
|
{
|
|
ME_BIOS_PAYLOAD_HOB *MbpHob;
|
|
|
|
DEBUG ((DEBUG_INFO, "%a invoked!\n", __FUNCTION__));
|
|
|
|
MbpHob = NULL;
|
|
MbpHob = GetFirstGuidHob (&gMeBiosPayloadHobGuid);
|
|
if (MbpHob != NULL) {
|
|
if (MbpHob->MeBiosPayload.FwPlatType.RuleData.Fields.IntelMeFwImageType != IntelMeCorporateFw ||
|
|
MbpHob->MeBiosPayload.FwCapsSku.FwCapabilities.Fields.Amt != 1) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "MBP HOB not found\n"));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
gMebxConfiguration.FwVersionMajor = (UINT16)(MbpHob->MeBiosPayload.FwVersionName.MajorVersion);
|
|
|
|
return MebxSetupInit (MbpHob->MeBiosPayload.FwPlatType.RuleData.Fields.PlatformBrand);
|
|
}
|
|
|