mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-29 12:35:53 +01:00
2263 lines
92 KiB
C
2263 lines
92 KiB
C
/** @file
|
|
|
|
The implementation of EFI Redfish Discover Protocol.
|
|
|
|
(C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
|
|
Copyright (c) 2022, AMD Incorporated. All rights reserved.
|
|
Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "RedfishDiscoverInternal.h"
|
|
|
|
LIST_ENTRY mRedfishDiscoverList;
|
|
LIST_ENTRY mRedfishInstanceList;
|
|
EFI_SMBIOS_PROTOCOL *mSmbios = NULL;
|
|
|
|
UINTN mNumNetworkInterface = 0;
|
|
UINTN mNumRestExInstance = 0;
|
|
LIST_ENTRY mEfiRedfishDiscoverNetworkInterface;
|
|
LIST_ENTRY mEfiRedfishDiscoverRestExInstance;
|
|
|
|
EFI_GUID mRedfishDiscoverTcp4InstanceGuid = EFI_REDFISH_DISCOVER_TCP4_INSTANCE_GUID;
|
|
EFI_GUID mRedfishDiscoverTcp6InstanceGuid = EFI_REDFISH_DISCOVER_TCP6_INSTANCE_GUID;
|
|
EFI_GUID mRedfishDiscoverRestExInstanceGuid = EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_GUID;
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Tcp4GetSubnetInfo (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Tcp6GetSubnetInfo (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
|
|
);
|
|
|
|
static REDFISH_DISCOVER_REQUIRED_PROTOCOL mRequiredProtocol[] = {
|
|
{
|
|
ProtocolTypeTcp4,
|
|
L"TCP4 Service Binding Protocol",
|
|
&gEfiTcp4ProtocolGuid,
|
|
&gEfiTcp4ServiceBindingProtocolGuid,
|
|
&mRedfishDiscoverTcp4InstanceGuid,
|
|
Tcp4GetSubnetInfo
|
|
},
|
|
{
|
|
ProtocolTypeTcp6,
|
|
L"TCP6 Service Binding Protocol",
|
|
&gEfiTcp6ProtocolGuid,
|
|
&gEfiTcp6ServiceBindingProtocolGuid,
|
|
&mRedfishDiscoverTcp6InstanceGuid,
|
|
Tcp6GetSubnetInfo
|
|
},
|
|
{
|
|
ProtocolTypeRestEx,
|
|
L"REST EX Service Binding Protocol",
|
|
&gEfiRestExProtocolGuid,
|
|
&gEfiRestExServiceBindingProtocolGuid,
|
|
&mRedfishDiscoverRestExInstanceGuid,
|
|
NULL
|
|
}
|
|
};
|
|
|
|
/**
|
|
This function creates REST EX instance for the found Resfish service.
|
|
by known owner handle.
|
|
|
|
@param[in] Instance EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
|
|
@param[in] Token Client token.
|
|
|
|
@retval NULL Instance not found.
|
|
@retval EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE The instance owned by this owner.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CreateRestExInstance (
|
|
IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
|
|
IN EFI_REDFISH_DISCOVERED_TOKEN *Token
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = RestExLibCreateChild (
|
|
Instance->NetworkInterface->OpenDriverControllerHandle,
|
|
Instance->Owner,
|
|
FixedPcdGetBool (PcdRedfishDiscoverAccessModeInBand) ? EfiRestExServiceInBandAccess : EfiRestExServiceOutOfBandAccess,
|
|
EfiRestExConfigHttp,
|
|
EfiRestExServiceRedfish,
|
|
&Token->DiscoverList.RedfishInstances->Information.RedfishRestExHandle
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function gets EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
|
|
by known owner handle.
|
|
|
|
@param[in] ImageHandle Image handle owns EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
|
|
@param[in] TargetNetworkInterface Target network interface used by this EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
|
|
@param[in] DiscoverFlags EFI_REDFISH_DISCOVER_FLAG
|
|
|
|
@retval NULL Instance not found.
|
|
@retval EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE The instance owned by this owner.
|
|
|
|
**/
|
|
EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *
|
|
GetInstanceByOwner (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *TargetNetworkInterface,
|
|
IN EFI_REDFISH_DISCOVER_FLAG DiscoverFlags
|
|
)
|
|
{
|
|
EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *ThisInstance;
|
|
|
|
if (IsListEmpty (&mRedfishDiscoverList)) {
|
|
return NULL;
|
|
}
|
|
|
|
ThisInstance =
|
|
(EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)GetFirstNode (&mRedfishDiscoverList);
|
|
while (TRUE) {
|
|
if ((ThisInstance->Owner == ImageHandle) &&
|
|
(ThisInstance->DiscoverFlags == DiscoverFlags) &&
|
|
(ThisInstance->NetworkInterface == TargetNetworkInterface))
|
|
{
|
|
return ThisInstance;
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mRedfishDiscoverList, &ThisInstance->Entry)) {
|
|
break;
|
|
}
|
|
|
|
ThisInstance =
|
|
(EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)GetNextNode (&mRedfishDiscoverList, &ThisInstance->Entry);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
This function gets the subnet information of this TCP4 instance.
|
|
|
|
@param[in] ImageHandle EFI handle with this image.
|
|
@param[in] Instance Instance of Network interface.
|
|
@retval EFI_STATUS Get subnet information successfully.
|
|
@retval Otherwise Fail to get subnet information.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Tcp4GetSubnetInfo (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_TCP4_PROTOCOL *Tcp4;
|
|
EFI_TCP4_CONFIG_DATA Tcp4CfgData;
|
|
EFI_TCP4_OPTION Tcp4Option;
|
|
EFI_IP4_MODE_DATA IpModedata;
|
|
UINT8 SubnetMaskIndex;
|
|
UINT8 BitMask;
|
|
UINT8 PrefixLength;
|
|
BOOLEAN GotPrefixLength;
|
|
|
|
if (Instance == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Tcp4 = (EFI_TCP4_PROTOCOL *)Instance->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
|
|
|
|
ZeroMem ((VOID *)&Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
|
|
ZeroMem ((VOID *)&Tcp4Option, sizeof (EFI_TCP4_OPTION));
|
|
// Give a local host IP address just for getting subnet information.
|
|
Tcp4CfgData.AccessPoint.UseDefaultAddress = TRUE;
|
|
Tcp4CfgData.AccessPoint.RemoteAddress.Addr[0] = 127;
|
|
Tcp4CfgData.AccessPoint.RemoteAddress.Addr[1] = 0;
|
|
Tcp4CfgData.AccessPoint.RemoteAddress.Addr[2] = 0;
|
|
Tcp4CfgData.AccessPoint.RemoteAddress.Addr[3] = 1;
|
|
Tcp4CfgData.AccessPoint.RemotePort = 80;
|
|
Tcp4CfgData.AccessPoint.ActiveFlag = TRUE;
|
|
|
|
Tcp4CfgData.ControlOption = &Tcp4Option;
|
|
Tcp4Option.ReceiveBufferSize = 65535;
|
|
Tcp4Option.SendBufferSize = 65535;
|
|
Tcp4Option.MaxSynBackLog = 5;
|
|
Tcp4Option.ConnectionTimeout = 60;
|
|
Tcp4Option.DataRetries = 12;
|
|
Tcp4Option.FinTimeout = 2;
|
|
Tcp4Option.KeepAliveProbes = 6;
|
|
Tcp4Option.KeepAliveTime = 7200;
|
|
Tcp4Option.KeepAliveInterval = 30;
|
|
Tcp4Option.EnableNagle = TRUE;
|
|
Status = Tcp4->Configure (Tcp4, &Tcp4CfgData);
|
|
if (EFI_ERROR (Status)) {
|
|
if (Status == EFI_NO_MAPPING) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
DEBUG ((DEBUG_ERROR, "%a: Can't get subnet information: %r\n", __func__, Status));
|
|
return Status;
|
|
}
|
|
|
|
Status = Tcp4->GetModeData (Tcp4, NULL, NULL, &IpModedata, NULL, NULL);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Can't get IP mode data information: %r\n", __func__, Status));
|
|
return Status;
|
|
}
|
|
|
|
IP4_COPY_ADDRESS (&Instance->SubnetMask, &IpModedata.ConfigData.SubnetMask);
|
|
Instance->SubnetAddr.v4.Addr[0] = IpModedata.ConfigData.StationAddress.Addr[0] & Instance->SubnetMask.v4.Addr[0];
|
|
Instance->SubnetAddr.v4.Addr[1] = IpModedata.ConfigData.StationAddress.Addr[1] & Instance->SubnetMask.v4.Addr[1];
|
|
Instance->SubnetAddr.v4.Addr[2] = IpModedata.ConfigData.StationAddress.Addr[2] & Instance->SubnetMask.v4.Addr[2];
|
|
Instance->SubnetAddr.v4.Addr[3] = IpModedata.ConfigData.StationAddress.Addr[3] & Instance->SubnetMask.v4.Addr[3];
|
|
//
|
|
// Calculate the subnet mask prefix.
|
|
//
|
|
GotPrefixLength = FALSE;
|
|
PrefixLength = 0;
|
|
SubnetMaskIndex = 0;
|
|
while (GotPrefixLength == FALSE && SubnetMaskIndex < 4) {
|
|
BitMask = 0x80;
|
|
while (BitMask != 0) {
|
|
if ((Instance->SubnetMask.v4.Addr[SubnetMaskIndex] & BitMask) != 0) {
|
|
PrefixLength++;
|
|
} else {
|
|
GotPrefixLength = TRUE;
|
|
break;
|
|
}
|
|
|
|
BitMask = BitMask >> 1;
|
|
}
|
|
|
|
SubnetMaskIndex++;
|
|
}
|
|
|
|
Instance->SubnetPrefixLength = PrefixLength;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function gets the subnet information of this TCP6 instance.
|
|
|
|
@param[in] ImageHandle EFI handle with this image.
|
|
@param[in] Instance Instance of Network interface.
|
|
@retval EFI_STATUS Get subnet information successfully.
|
|
@retval Otherwise Fail to get subnet information.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Tcp6GetSubnetInfo (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_TCP6_PROTOCOL *Tcp6;
|
|
EFI_IP6_MODE_DATA IpModedata;
|
|
|
|
if (Instance == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Tcp6 = (EFI_TCP6_PROTOCOL *)Instance->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
|
|
|
|
ZeroMem ((VOID *)&IpModedata, sizeof (EFI_IP6_MODE_DATA));
|
|
Status = Tcp6->GetModeData (Tcp6, NULL, NULL, &IpModedata, NULL, NULL);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Can't get IP mode data information: %r\n", __func__, Status));
|
|
return Status;
|
|
}
|
|
|
|
if (IpModedata.AddressCount == 0) {
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: No IPv6 address configured.\n", __func__));
|
|
Instance->SubnetAddrInfoIPv6Number = 0;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (Instance->SubnetAddrInfoIPv6 != NULL) {
|
|
FreePool (Instance->SubnetAddrInfoIPv6);
|
|
Instance->SubnetAddrInfoIPv6 = NULL;
|
|
}
|
|
|
|
Instance->SubnetAddrInfoIPv6 = AllocateZeroPool (IpModedata.AddressCount * sizeof (EFI_IP6_ADDRESS_INFO));
|
|
if (Instance->SubnetAddrInfoIPv6 == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Failed to allocate memory for IPv6 subnet address information\n", __func__));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Instance->SubnetAddrInfoIPv6Number = IpModedata.AddressCount;
|
|
if ((IpModedata.AddressCount != 0) && (IpModedata.AddressList != NULL)) {
|
|
CopyMem (
|
|
(VOID *)Instance->SubnetAddrInfoIPv6,
|
|
(VOID *)&IpModedata.AddressList,
|
|
IpModedata.AddressCount * sizeof (EFI_IP6_ADDRESS_INFO)
|
|
);
|
|
FreePool (IpModedata.AddressList);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function searches EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
|
|
instance with the given EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
|
|
|
|
@param[in] TargetNetworkInterface EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
|
|
NULL for all EFI_REDFISH_DISCOVER_NETWORK_INTERFACEs.
|
|
|
|
@retval Non-NULL EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL is returned.
|
|
@retval NULL Non of EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance is returned.
|
|
**/
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *
|
|
GetTargetNetworkInterfaceInternal (
|
|
IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *TargetNetworkInterface
|
|
)
|
|
{
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
|
|
|
|
if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
|
|
return NULL;
|
|
}
|
|
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
|
|
while (TRUE) {
|
|
if ((MAC_COMPARE (ThisNetworkInterface, TargetNetworkInterface)) &&
|
|
(VALID_TCP6 (TargetNetworkInterface, ThisNetworkInterface) ||
|
|
VALID_TCP4 (TargetNetworkInterface, ThisNetworkInterface)))
|
|
{
|
|
return ThisNetworkInterface;
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
|
|
return NULL;
|
|
}
|
|
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
This function searches EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
|
|
instance with the given Controller handle.
|
|
|
|
@param[in] ControllerHandle The controller handle associated with network interface.
|
|
|
|
@retval Non-NULL EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL is returned.
|
|
@retval NULL Non of EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance is returned.
|
|
**/
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *
|
|
GetTargetNetworkInterfaceInternalByController (
|
|
IN EFI_HANDLE ControllerHandle
|
|
)
|
|
{
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
|
|
|
|
if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
|
|
return NULL;
|
|
}
|
|
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
|
|
while (TRUE) {
|
|
if (ThisNetworkInterface->OpenDriverControllerHandle == ControllerHandle) {
|
|
return ThisNetworkInterface;
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
|
|
return NULL;
|
|
}
|
|
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
This function validate if target network interface is ready for discovering
|
|
Redfish service.
|
|
|
|
@param[in] TargetNetworkInterface EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
|
|
NULL for all EFI_REDFISH_DISCOVER_NETWORK_INTERFACEs.
|
|
@param[in] Flags EFI_REDFISH_DISCOVER_FLAG
|
|
|
|
@retval EFI_SUCCESS Target network interface is ready to use.
|
|
@retval EFI_UNSUPPORTED Target network interface is not ready to use.
|
|
**/
|
|
EFI_STATUS
|
|
ValidateTargetNetworkInterface (
|
|
IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *TargetNetworkInterface,
|
|
IN EFI_REDFISH_DISCOVER_FLAG Flags
|
|
)
|
|
{
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
|
|
|
|
if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface) && (TargetNetworkInterface == NULL)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (TargetNetworkInterface == NULL) {
|
|
return EFI_SUCCESS; // Return EFI_SUCCESS if no network interface is specified.
|
|
}
|
|
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
|
|
while (TRUE) {
|
|
if (MAC_COMPARE (ThisNetworkInterface, TargetNetworkInterface)) {
|
|
break;
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
|
|
}
|
|
|
|
if ((Flags & EFI_REDFISH_DISCOVER_SSDP) != 0) {
|
|
// Validate if UDP4/6 is supported on the given network interface.
|
|
// SSDP is not supported.
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle == NULL) {
|
|
return EFI_UNSUPPORTED; // The required protocol on this network interface is not found.
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function returns number of network interface instance.
|
|
|
|
@retval UINTN Number of network interface instances.
|
|
**/
|
|
UINTN
|
|
NumberOfNetworkInterface (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN Num;
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
|
|
|
|
if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
|
|
return 0;
|
|
}
|
|
|
|
Num = 1;
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
|
|
while (TRUE) {
|
|
if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
|
|
break;
|
|
}
|
|
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
|
|
Num++;
|
|
}
|
|
|
|
return Num;
|
|
}
|
|
|
|
/**
|
|
This function checks the IP version supported on this
|
|
network interface.
|
|
|
|
@param[in] ThisNetworkInterface EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
|
|
|
|
@retval TRUE Is IPv6, otherwise IPv4.
|
|
|
|
**/
|
|
BOOLEAN
|
|
CheckIsIpVersion6 (
|
|
IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface
|
|
)
|
|
{
|
|
if (ThisNetworkInterface->NetworkProtocolType == ProtocolTypeTcp6) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
This function returns the IP type supported by the Host Interface.
|
|
|
|
@retval 00h is Unknown
|
|
01h is Ipv4
|
|
02h is Ipv6
|
|
|
|
**/
|
|
STATIC
|
|
UINT8
|
|
GetHiIpProtocolType (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
REDFISH_OVER_IP_PROTOCOL_DATA *Data;
|
|
REDFISH_INTERFACE_DATA *DeviceDescriptor;
|
|
|
|
Data = NULL;
|
|
DeviceDescriptor = NULL;
|
|
if (mSmbios == NULL) {
|
|
Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&mSmbios);
|
|
if (EFI_ERROR (Status)) {
|
|
return REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
Status = RedfishGetHostInterfaceProtocolData (mSmbios, &DeviceDescriptor, &Data); // Search for SMBIOS type 42h
|
|
if (!EFI_ERROR (Status) && (Data != NULL) &&
|
|
(Data->HostIpAssignmentType == RedfishHostIpAssignmentStatic))
|
|
{
|
|
return Data->HostIpAddressFormat;
|
|
}
|
|
|
|
return REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_UNKNOWN;
|
|
}
|
|
|
|
/**
|
|
Check if Network Protocol Type matches with SMBIOS Type 42 IP Address Type.
|
|
|
|
@param[in] NetworkProtocolType The Network Protocol Type to check with.
|
|
@param[in] IpType The Host IP Address Type from SMBIOS Type 42.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
FilterProtocol (
|
|
IN UINT32 NetworkProtocolType,
|
|
IN UINT8 IpType
|
|
)
|
|
{
|
|
if (NetworkProtocolType == ProtocolTypeTcp4) {
|
|
return IpType != REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP4;
|
|
}
|
|
|
|
if (NetworkProtocolType == ProtocolTypeTcp6) {
|
|
return IpType != REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP6;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
This function discover Redfish service through SMBIOS host interface.
|
|
|
|
@param[in] Instance EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
|
|
|
|
@retval EFI_SUCCESS Redfish service is discovered through SMBIOS Host interface.
|
|
@retval Others Fail to discover Redfish service through SMBIOS host interface
|
|
|
|
**/
|
|
EFI_STATUS
|
|
DiscoverRedfishHostInterface (
|
|
IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
REDFISH_OVER_IP_PROTOCOL_DATA *Data;
|
|
REDFISH_INTERFACE_DATA *DeviceDescriptor;
|
|
CHAR8 UuidStr[sizeof "00000000-0000-0000-0000-000000000000" + 1];
|
|
CHAR16 Ipv6Str[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1];
|
|
CHAR8 RedfishServiceLocateStr[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1];
|
|
UINTN StrSize;
|
|
UINTN MacCompareStatus;
|
|
BOOLEAN IsHttps;
|
|
|
|
Data = NULL;
|
|
DeviceDescriptor = NULL;
|
|
|
|
if (mSmbios == NULL) {
|
|
Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&mSmbios);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
Status = RedfishGetHostInterfaceProtocolData (mSmbios, &DeviceDescriptor, &Data); // Search for SMBIOS type 42h
|
|
if (!EFI_ERROR (Status) && (Data != NULL) && (DeviceDescriptor != NULL)) {
|
|
// Check IP Type and skip an unnecessary network protocol if does not match
|
|
if (FilterProtocol (Instance->NetworkInterface->NetworkProtocolType, Data->HostIpAddressFormat)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Check if we can reach out Redfish service using this network interface.
|
|
// Check with MAC address using Device Descriptor Data Device Type 04 and Type 05.
|
|
// Those two types of Redfish host interface device has MAC information.
|
|
//
|
|
if (DeviceDescriptor->DeviceType == REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2) {
|
|
MacCompareStatus = CompareMem (&Instance->NetworkInterface->MacAddress, &DeviceDescriptor->DeviceDescriptor.PciPcieDeviceV2.MacAddress, 6);
|
|
} else if (DeviceDescriptor->DeviceType == REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2) {
|
|
MacCompareStatus = CompareMem (&Instance->NetworkInterface->MacAddress, &DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.MacAddress, 6);
|
|
} else {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (MacCompareStatus != 0) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Instance->HostAddrFormat = Data->HostIpAddressFormat;
|
|
if (Data->HostIpAddressFormat == REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP4) {
|
|
IP4_COPY_ADDRESS ((VOID *)&Instance->HostIpAddress.v4, (VOID *)Data->HostIpAddress);
|
|
IP4_COPY_ADDRESS ((VOID *)&Instance->HostSubnetMask.v4, (VOID *)Data->HostIpMask);
|
|
|
|
if (EFI_IP4_EQUAL (&Instance->HostIpAddress.v4, &mZeroIp4Addr)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: invalid host IP address: ", __func__));
|
|
DumpIpv4Address (DEBUG_ERROR, &Instance->HostIpAddress.v4);
|
|
//
|
|
// Invalid IP address detected. Change address format to Unknown and use system default address.
|
|
//
|
|
Instance->HostAddrFormat = REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_UNKNOWN;
|
|
}
|
|
|
|
if (!IP4_IS_VALID_NETMASK (NTOHL (EFI_IP4 (Instance->HostSubnetMask.v4)))) {
|
|
DEBUG ((DEBUG_ERROR, "%a: invalid subnet mask address: ", __func__));
|
|
DumpIpv4Address (DEBUG_ERROR, &Instance->HostSubnetMask.v4);
|
|
//
|
|
// Invalid subnet mast address detected. Change address format to Unknown and use system default address.
|
|
//
|
|
Instance->HostAddrFormat = REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_UNKNOWN;
|
|
}
|
|
} else if (Data->HostIpAddressFormat == REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP6) {
|
|
IP6_COPY_ADDRESS ((VOID *)&Instance->HostIpAddress.v6, (VOID *)Data->HostIpAddress);
|
|
}
|
|
|
|
if (Data->RedfishServiceIpAddressFormat == REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP4) {
|
|
IP4_COPY_ADDRESS ((VOID *)&Instance->TargetIpAddress.v4, (VOID *)Data->RedfishServiceIpAddress);
|
|
|
|
if (EFI_IP4_EQUAL (&Instance->TargetIpAddress.v4, &mZeroIp4Addr)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: invalid service IP address: ", __func__));
|
|
DumpIpv4Address (DEBUG_ERROR, &Instance->TargetIpAddress.v4);
|
|
}
|
|
} else {
|
|
IP6_COPY_ADDRESS ((VOID *)&Instance->TargetIpAddress.v6, (VOID *)Data->RedfishServiceIpAddress);
|
|
}
|
|
|
|
if (Instance->HostIntfValidation) {
|
|
DEBUG ((DEBUG_ERROR, "%a:Send UPnP unicast SSDP to validate this Redfish Host Interface is not supported.\n", __func__));
|
|
Status = EFI_UNSUPPORTED;
|
|
} else {
|
|
//
|
|
// Add this instance to list without detail information of Redfish
|
|
// service.
|
|
//
|
|
IsHttps = FALSE;
|
|
if (Data->RedfishServiceIpPort == 443) {
|
|
IsHttps = TRUE;
|
|
}
|
|
|
|
StrSize = sizeof (UuidStr);
|
|
AsciiSPrint (UuidStr, StrSize, "%g", &Data->ServiceUuid);
|
|
//
|
|
// Generate Redfish service location string.
|
|
//
|
|
if (Data->RedfishServiceIpAddressFormat == REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP6) {
|
|
NetLibIp6ToStr ((IPv6_ADDRESS *)&Data->RedfishServiceIpAddress, Ipv6Str, sizeof (Ipv6Str));
|
|
if ((Data->RedfishServiceIpPort == 0) || (IsHttps == TRUE)) {
|
|
AsciiSPrintUnicodeFormat (
|
|
RedfishServiceLocateStr,
|
|
sizeof (RedfishServiceLocateStr),
|
|
L"%s",
|
|
Ipv6Str
|
|
);
|
|
} else {
|
|
AsciiSPrintUnicodeFormat (
|
|
RedfishServiceLocateStr,
|
|
sizeof (RedfishServiceLocateStr),
|
|
L"[%s]:%d",
|
|
Ipv6Str,
|
|
Data->RedfishServiceIpPort
|
|
);
|
|
}
|
|
} else {
|
|
if ((Data->RedfishServiceIpPort == 0) || (IsHttps == TRUE)) {
|
|
AsciiSPrint (
|
|
RedfishServiceLocateStr,
|
|
sizeof (RedfishServiceLocateStr),
|
|
"%d.%d.%d.%d",
|
|
Data->RedfishServiceIpAddress[0],
|
|
Data->RedfishServiceIpAddress[1],
|
|
Data->RedfishServiceIpAddress[2],
|
|
Data->RedfishServiceIpAddress[3]
|
|
);
|
|
} else {
|
|
AsciiSPrint (
|
|
RedfishServiceLocateStr,
|
|
sizeof (RedfishServiceLocateStr),
|
|
"%d.%d.%d.%d:%d",
|
|
Data->RedfishServiceIpAddress[0],
|
|
Data->RedfishServiceIpAddress[1],
|
|
Data->RedfishServiceIpAddress[2],
|
|
Data->RedfishServiceIpAddress[3],
|
|
Data->RedfishServiceIpPort
|
|
);
|
|
}
|
|
}
|
|
|
|
Status = AddAndSignalNewRedfishService (
|
|
Instance,
|
|
NULL,
|
|
RedfishServiceLocateStr,
|
|
UuidStr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
IsHttps
|
|
);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
The function adds a new found Redfish service to internal list and
|
|
notify client.
|
|
|
|
@param[in] Instance EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
|
|
@param[in] RedfishVersion Redfish version.
|
|
@param[in] RedfishLocation Redfish location.
|
|
@param[in] Uuid Service UUID string.
|
|
@param[in] Os OS string.
|
|
@param[in] OsVer OS version string.
|
|
@param[in] Product Product string.
|
|
@param[in] ProductVer Product version string.
|
|
@param[in] UseHttps Redfish service requires secured connection.
|
|
@retval EFI_SUCCESS Redfish service is added to list successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
AddAndSignalNewRedfishService (
|
|
IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
|
|
IN UINTN *RedfishVersion OPTIONAL,
|
|
IN CHAR8 *RedfishLocation OPTIONAL,
|
|
IN CHAR8 *Uuid OPTIONAL,
|
|
IN CHAR8 *Os OPTIONAL,
|
|
IN CHAR8 *OsVer OPTIONAL,
|
|
IN CHAR8 *Product OPTIONAL,
|
|
IN CHAR8 *ProductVer OPTIONAL,
|
|
IN BOOLEAN UseHttps
|
|
)
|
|
{
|
|
BOOLEAN NewFound;
|
|
BOOLEAN InfoRefresh;
|
|
BOOLEAN RestExOpened;
|
|
BOOLEAN DeleteRestEx;
|
|
EFI_STATUS Status;
|
|
EFI_REDFISH_DISCOVERED_INTERNAL_LIST *DiscoveredList;
|
|
EFI_REDFISH_DISCOVERED_INSTANCE *DiscoveredInstance;
|
|
CHAR16 *Char16Uuid;
|
|
EFI_REST_EX_PROTOCOL *RestEx;
|
|
EFI_REST_EX_HTTP_CONFIG_DATA *RestExHttpConfigData;
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NetworkInterface;
|
|
|
|
NewFound = TRUE;
|
|
InfoRefresh = FALSE;
|
|
Char16Uuid = NULL;
|
|
RestExOpened = FALSE;
|
|
DeleteRestEx = FALSE;
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a:Add this instance to Redfish instance list.\n", __func__));
|
|
|
|
if (Uuid != NULL) {
|
|
Char16Uuid = (CHAR16 *)AllocateZeroPool (AsciiStrSize ((const CHAR8 *)Uuid) * sizeof (CHAR16));
|
|
AsciiStrToUnicodeStrS ((const CHAR8 *)Uuid, Char16Uuid, AsciiStrSize ((const CHAR8 *)Uuid) * sizeof (CHAR16));
|
|
}
|
|
|
|
DiscoveredList = NULL;
|
|
DiscoveredInstance = NULL;
|
|
RestExHttpConfigData = NULL;
|
|
|
|
NetworkInterface = Instance->NetworkInterface;
|
|
if (!IsListEmpty (&mRedfishInstanceList)) {
|
|
//
|
|
// Is this a duplicate redfish service.
|
|
//
|
|
DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetFirstNode (&mRedfishInstanceList);
|
|
NewFound = FALSE;
|
|
do {
|
|
if ((Char16Uuid == NULL) || (DiscoveredList->Instance->Information.Uuid == NULL)) {
|
|
//
|
|
// Check if this Redfish instance already found using IP address.
|
|
//
|
|
if (!CheckIsIpVersion6 (NetworkInterface)) {
|
|
if (CompareMem (
|
|
(VOID *)&Instance->TargetIpAddress.v4,
|
|
(VOID *)&DiscoveredList->Instance->Information.RedfishHostIpAddress.v4,
|
|
sizeof (EFI_IPv4_ADDRESS)
|
|
) == 0)
|
|
{
|
|
DiscoveredInstance = DiscoveredList->Instance;
|
|
if ((DiscoveredList->Instance->Information.Uuid == NULL) &&
|
|
(Char16Uuid != NULL))
|
|
{
|
|
InfoRefresh = TRUE;
|
|
DiscoveredInstance = DiscoveredList->Instance;
|
|
DEBUG ((DEBUG_MANAGEABILITY, "*** This Redfish Service information refresh ***\n"));
|
|
}
|
|
|
|
break;
|
|
}
|
|
} else {
|
|
if (CompareMem (
|
|
(VOID *)&Instance->TargetIpAddress.v6,
|
|
(VOID *)&DiscoveredList->Instance->Information.RedfishHostIpAddress.v6,
|
|
sizeof (EFI_IPv6_ADDRESS)
|
|
) == 0)
|
|
{
|
|
DiscoveredInstance = DiscoveredList->Instance;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// Check if this Redfish instance already found using UUID.
|
|
//
|
|
if (StrCmp ((const CHAR16 *)Char16Uuid, (const CHAR16 *)DiscoveredList->Instance->Information.Uuid) == 0) {
|
|
DiscoveredInstance = DiscoveredList->Instance;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mRedfishInstanceList, &DiscoveredList->NextInstance)) {
|
|
NewFound = TRUE;
|
|
break;
|
|
}
|
|
|
|
DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetNextNode (&mRedfishInstanceList, &DiscoveredList->NextInstance);
|
|
} while (TRUE);
|
|
}
|
|
|
|
if (NewFound || InfoRefresh) {
|
|
if (!InfoRefresh) {
|
|
DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVERED_INTERNAL_LIST));
|
|
if (DiscoveredList == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
InitializeListHead (&DiscoveredList->NextInstance);
|
|
DiscoveredInstance = (EFI_REDFISH_DISCOVERED_INSTANCE *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVERED_INSTANCE));
|
|
if (DiscoveredInstance == NULL) {
|
|
FreePool ((VOID *)DiscoveredList);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
}
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "*** Redfish Service Information ***\n"));
|
|
|
|
DiscoveredInstance->Information.UseHttps = UseHttps;
|
|
if (RedfishVersion != NULL) {
|
|
DiscoveredInstance->Information.RedfishVersion = *RedfishVersion;
|
|
DEBUG ((DEBUG_MANAGEABILITY, "Redfish service version: %d.\n", DiscoveredInstance->Information.RedfishVersion));
|
|
}
|
|
|
|
if (RedfishLocation != NULL) {
|
|
DiscoveredInstance->Information.Location = (CHAR16 *)AllocatePool (AsciiStrSize ((const CHAR8 *)RedfishLocation) * sizeof (CHAR16));
|
|
AsciiStrToUnicodeStrS ((const CHAR8 *)RedfishLocation, DiscoveredInstance->Information.Location, AsciiStrSize ((const CHAR8 *)RedfishLocation) * sizeof (CHAR16));
|
|
DEBUG ((DEBUG_MANAGEABILITY, "Redfish service location: %s.\n", DiscoveredInstance->Information.Location));
|
|
}
|
|
|
|
if (Uuid != NULL) {
|
|
DiscoveredInstance->Information.Uuid = (CHAR16 *)AllocatePool (AsciiStrSize ((const CHAR8 *)Uuid) * sizeof (CHAR16));
|
|
AsciiStrToUnicodeStrS ((const CHAR8 *)Uuid, DiscoveredInstance->Information.Uuid, AsciiStrSize ((const CHAR8 *)Uuid) * sizeof (CHAR16));
|
|
DEBUG ((DEBUG_MANAGEABILITY, "Service UUID: %s.\n", DiscoveredInstance->Information.Uuid));
|
|
}
|
|
|
|
if (Os != NULL) {
|
|
DiscoveredInstance->Information.Os = (CHAR16 *)AllocatePool (AsciiStrSize ((const CHAR8 *)Os) * sizeof (CHAR16));
|
|
AsciiStrToUnicodeStrS ((const CHAR8 *)Os, DiscoveredInstance->Information.Os, AsciiStrSize ((const CHAR8 *)Os) * sizeof (CHAR16));
|
|
DEBUG ((DEBUG_MANAGEABILITY, "Redfish service OS: %s, Version:%s.\n", DiscoveredInstance->Information.Os, DiscoveredInstance->Information.OsVersion));
|
|
}
|
|
|
|
if (OsVer != NULL) {
|
|
DiscoveredInstance->Information.OsVersion = (CHAR16 *)AllocatePool (AsciiStrSize ((const CHAR8 *)OsVer) * sizeof (CHAR16));
|
|
AsciiStrToUnicodeStrS ((const CHAR8 *)OsVer, DiscoveredInstance->Information.OsVersion, AsciiStrSize ((const CHAR8 *)OsVer) * sizeof (CHAR16));
|
|
}
|
|
|
|
if ((Product != NULL) && (ProductVer != NULL)) {
|
|
DiscoveredInstance->Information.Product = (CHAR16 *)AllocatePool (AsciiStrSize ((const CHAR8 *)Product) * sizeof (CHAR16));
|
|
AsciiStrToUnicodeStrS ((const CHAR8 *)Product, DiscoveredInstance->Information.Product, AsciiStrSize ((const CHAR8 *)Product) * sizeof (CHAR16));
|
|
DiscoveredInstance->Information.ProductVer = (CHAR16 *)AllocatePool (AsciiStrSize ((const CHAR8 *)ProductVer) * sizeof (CHAR16));
|
|
AsciiStrToUnicodeStrS ((const CHAR8 *)ProductVer, DiscoveredInstance->Information.ProductVer, AsciiStrSize ((const CHAR8 *)ProductVer) * sizeof (CHAR16));
|
|
DEBUG ((DEBUG_MANAGEABILITY, "Redfish service product: %s, Version:%s.\n", DiscoveredInstance->Information.Product, DiscoveredInstance->Information.ProductVer));
|
|
}
|
|
|
|
if (RedfishLocation == NULL) {
|
|
// This is the Redfish reported from SMBIOS 42h
|
|
// without validation.
|
|
|
|
IP4_COPY_ADDRESS ((VOID *)&DiscoveredInstance->Information.RedfishHostIpAddress.v4, (VOID *)&Instance->TargetIpAddress.v4);
|
|
}
|
|
|
|
if (!InfoRefresh) {
|
|
DiscoveredList->Instance = DiscoveredInstance;
|
|
InsertTailList (&mRedfishInstanceList, &DiscoveredList->NextInstance);
|
|
}
|
|
|
|
DiscoveredInstance->Status = EFI_SUCCESS;
|
|
} else {
|
|
if (DiscoveredList != NULL) {
|
|
DEBUG ((DEBUG_MANAGEABILITY, "*** This Redfish Service was already found ***\n"));
|
|
if (DiscoveredInstance->Information.Uuid != NULL) {
|
|
DEBUG ((DEBUG_MANAGEABILITY, "Service UUID: %s.\n", DiscoveredInstance->Information.Uuid));
|
|
} else {
|
|
DEBUG ((DEBUG_MANAGEABILITY, "Service UUID: unknown.\n"));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Char16Uuid != NULL) {
|
|
FreePool ((VOID *)Char16Uuid);
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
if (NewFound || InfoRefresh) {
|
|
//
|
|
// Build up EFI_REDFISH_DISCOVERED_LIST in token.
|
|
//
|
|
Instance->DiscoverToken->DiscoverList.NumberOfServiceFound = 1;
|
|
Instance->DiscoverToken->DiscoverList.RedfishInstances = DiscoveredInstance;
|
|
DiscoveredInstance->Status = EFI_SUCCESS;
|
|
if (!InfoRefresh) {
|
|
Status = CreateRestExInstance (Instance, Instance->DiscoverToken); // Create REST EX child.
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a:Can't create REST EX child instance.\n", __func__));
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
Status = gBS->OpenProtocol (
|
|
// Configure local host information.
|
|
Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
|
|
&gEfiRestExProtocolGuid,
|
|
(VOID **)&RestEx,
|
|
Instance->NetworkInterface->OpenDriverAgentHandle,
|
|
Instance->NetworkInterface->OpenDriverControllerHandle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DeleteRestEx = TRUE;
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
RestExOpened = TRUE;
|
|
RestExHttpConfigData = AllocateZeroPool (sizeof (EFI_REST_EX_HTTP_CONFIG_DATA));
|
|
if (RestExHttpConfigData == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
DeleteRestEx = TRUE;
|
|
goto EXIT_FREE_CONFIG_DATA;
|
|
}
|
|
|
|
RestExHttpConfigData->SendReceiveTimeout = PcdGet32 (PcdRedfishSendReceiveTimeout);
|
|
RestExHttpConfigData->HttpConfigData.HttpVersion = HttpVersion11;
|
|
RestExHttpConfigData->HttpConfigData.LocalAddressIsIPv6 = CheckIsIpVersion6 (NetworkInterface);
|
|
if (RestExHttpConfigData->HttpConfigData.LocalAddressIsIPv6) {
|
|
RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node = AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT));
|
|
if (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT_FREE_CONFIG_DATA;
|
|
}
|
|
|
|
if (Instance->HostAddrFormat == REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP6) {
|
|
IP6_COPY_ADDRESS (&RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node->LocalAddress, &Instance->HostIpAddress.v6);
|
|
}
|
|
} else {
|
|
RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node = AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT));
|
|
if (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT_FREE_CONFIG_DATA;
|
|
}
|
|
|
|
if (Instance->HostAddrFormat == REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP4) {
|
|
RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node->UseDefaultAddress = FALSE;
|
|
IP4_COPY_ADDRESS (&RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node->LocalAddress, &Instance->HostIpAddress.v4);
|
|
IP4_COPY_ADDRESS (&RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node->LocalSubnet, &Instance->HostSubnetMask.v4);
|
|
} else {
|
|
RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node->UseDefaultAddress = TRUE;
|
|
}
|
|
}
|
|
|
|
Status = RestEx->Configure (
|
|
RestEx,
|
|
(EFI_REST_EX_CONFIG_DATA)(UINT8 *)RestExHttpConfigData
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a:REST EX configured..\n", __func__));
|
|
DeleteRestEx = TRUE;
|
|
goto EXIT_FREE_ALL;
|
|
}
|
|
|
|
//
|
|
// Signal client, close REST EX before signaling client.
|
|
//
|
|
if (RestExOpened) {
|
|
gBS->CloseProtocol (
|
|
Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
|
|
&gEfiRestExProtocolGuid,
|
|
Instance->NetworkInterface->OpenDriverAgentHandle,
|
|
Instance->NetworkInterface->OpenDriverControllerHandle
|
|
);
|
|
RestExOpened = FALSE;
|
|
}
|
|
}
|
|
|
|
Status = gBS->SignalEvent (Instance->DiscoverToken->Event);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a:No event to signal!\n", __func__));
|
|
}
|
|
}
|
|
|
|
EXIT_FREE_ALL:;
|
|
if ((RestExHttpConfigData != NULL) && (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node != NULL)) {
|
|
FreePool (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node);
|
|
}
|
|
|
|
EXIT_FREE_CONFIG_DATA:;
|
|
if (RestExHttpConfigData != NULL) {
|
|
FreePool ((VOID *)RestExHttpConfigData);
|
|
}
|
|
|
|
if (RestExOpened) {
|
|
gBS->CloseProtocol (
|
|
Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
|
|
&gEfiRestExProtocolGuid,
|
|
Instance->NetworkInterface->OpenDriverAgentHandle,
|
|
Instance->NetworkInterface->OpenDriverControllerHandle
|
|
);
|
|
}
|
|
|
|
ERROR_EXIT:;
|
|
if (DeleteRestEx && RestExOpened) {
|
|
gBS->CloseProtocol (
|
|
Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
|
|
&gEfiRestExProtocolGuid,
|
|
Instance->NetworkInterface->OpenDriverAgentHandle,
|
|
Instance->NetworkInterface->OpenDriverControllerHandle
|
|
);
|
|
}
|
|
|
|
ON_EXIT:;
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function gets the subnet information of this network interface instance.
|
|
can discover Redfish service on it.
|
|
|
|
@param[in] Instance EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance.
|
|
@param[in] ImageHandle EFI Image handle request the network interface list.
|
|
|
|
@retval EFI_SUCCESS
|
|
|
|
**/
|
|
EFI_STATUS
|
|
NetworkInterfaceGetSubnetInfo (
|
|
IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance,
|
|
IN EFI_HANDLE ImageHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 ProtocolType;
|
|
UINT32 IPv6InfoIndex;
|
|
EFI_IP6_ADDRESS_INFO *ThisSubnetAddrInfoIPv6;
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NewNetworkInterface;
|
|
|
|
if (Instance->GotSubnetInfo) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
ProtocolType = Instance->NetworkProtocolType;
|
|
if ((mRequiredProtocol[ProtocolType].GetSubnetInfo != NULL) && (Instance->GotSubnetInfo == FALSE)) {
|
|
Status = mRequiredProtocol[ProtocolType].GetSubnetInfo (
|
|
ImageHandle,
|
|
Instance
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a:Failed to get Subnet information.\n", __func__));
|
|
return Status;
|
|
} else {
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a:MAC address: %s\n", __func__, Instance->StrMacAddr));
|
|
if (CheckIsIpVersion6 (Instance)) {
|
|
if (Instance->SubnetAddrInfoIPv6Number == 0) {
|
|
DEBUG ((DEBUG_WARN, "%a: There is no Subnet information for IPv6 network interface.\n", __func__));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
ThisSubnetAddrInfoIPv6 = Instance->SubnetAddrInfoIPv6; // First IPv6 address information.
|
|
IP6_COPY_ADDRESS (&Instance->SubnetAddr.v6, &ThisSubnetAddrInfoIPv6->Address);
|
|
Instance->SubnetPrefixLength = ThisSubnetAddrInfoIPv6->PrefixLength;
|
|
DEBUG ((
|
|
DEBUG_MANAGEABILITY,
|
|
" IPv6 Subnet ID:%d, Prefix length: %d.\n",
|
|
ThisSubnetAddrInfoIPv6->Address.Addr[7] + (UINT16)ThisSubnetAddrInfoIPv6->Address.Addr[6] * 256,
|
|
ThisSubnetAddrInfoIPv6->PrefixLength
|
|
)
|
|
);
|
|
//
|
|
// If this is IPv6, then we may have to propagate network interface for IPv6 network scopes
|
|
// according to the Ipv6 address information.
|
|
//
|
|
ThisSubnetAddrInfoIPv6++;
|
|
for (IPv6InfoIndex = 0; IPv6InfoIndex < Instance->SubnetAddrInfoIPv6Number - 1; IPv6InfoIndex++) {
|
|
//
|
|
// Build up additional EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instances.
|
|
//
|
|
NewNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL));
|
|
if (NewNetworkInterface != NULL) {
|
|
CopyMem ((VOID *)NewNetworkInterface, (VOID *)Instance, sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL)); // Clone information of first instance.
|
|
IP6_COPY_ADDRESS (&NewNetworkInterface->SubnetAddr.v6, &ThisSubnetAddrInfoIPv6->Address);
|
|
NewNetworkInterface->SubnetPrefixLength = ThisSubnetAddrInfoIPv6->PrefixLength;
|
|
NewNetworkInterface->GotSubnetInfo = TRUE;
|
|
InsertTailList (&mEfiRedfishDiscoverNetworkInterface, &NewNetworkInterface->Entry);
|
|
ThisSubnetAddrInfoIPv6++;
|
|
mNumNetworkInterface++;
|
|
DEBUG ((
|
|
DEBUG_MANAGEABILITY,
|
|
" IPv6 Subnet ID:%d, Prefix length: %d.\n",
|
|
ThisSubnetAddrInfoIPv6->Address.Addr[7] + (UINT16)ThisSubnetAddrInfoIPv6->Address.Addr[6] * 256,
|
|
ThisSubnetAddrInfoIPv6->PrefixLength
|
|
)
|
|
);
|
|
} else {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
}
|
|
} else {
|
|
DEBUG ((
|
|
DEBUG_MANAGEABILITY,
|
|
" IPv4 Subnet:%d.%d.%d.%d Subnet mask: %d.%d.%d.%d.\n",
|
|
Instance->SubnetAddr.v4.Addr[0],
|
|
Instance->SubnetAddr.v4.Addr[1],
|
|
Instance->SubnetAddr.v4.Addr[2],
|
|
Instance->SubnetAddr.v4.Addr[3],
|
|
Instance->SubnetMask.v4.Addr[0],
|
|
Instance->SubnetMask.v4.Addr[1],
|
|
Instance->SubnetMask.v4.Addr[2],
|
|
Instance->SubnetMask.v4.Addr[3]
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
Instance->GotSubnetInfo = TRUE; // Only try to get Subnet Info once.
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function gets the network interface list which Redfish discover protocol
|
|
can discover Redfish service on it.
|
|
|
|
@param[in] This EFI_REDFISH_DISCOVER_PROTOCOL instance.
|
|
@param[in] ImageHandle EFI Image handle request the network interface list,
|
|
@param[out] NumberOfNetworkIntfs Number of network interfaces can do Redfish service discovery.
|
|
@param[out] NetworkIntfInstances Network interface instances. It's an array of instance. The number of entries
|
|
in array is indicated by NumberOfNetworkIntfs.
|
|
Caller has to release the memory
|
|
allocated by Redfish discover protocol.
|
|
|
|
@retval EFI_SUCCESS The information of network interface is returned in NumberOfNetworkIntfs and
|
|
NetworkIntfInstances.
|
|
@retval Others Fail to return the information of network interface.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RedfishServiceGetNetworkInterface (
|
|
IN EFI_REDFISH_DISCOVER_PROTOCOL *This,
|
|
IN EFI_HANDLE ImageHandle,
|
|
OUT UINTN *NumberOfNetworkIntfs,
|
|
OUT EFI_REDFISH_DISCOVER_NETWORK_INTERFACE **NetworkIntfInstances
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterfaceIntn;
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *ThisNetworkInterface;
|
|
EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *RestExInstance;
|
|
|
|
if ((This == NULL) || (NetworkIntfInstances == NULL) || (NumberOfNetworkIntfs == NULL) ||
|
|
(ImageHandle == NULL))
|
|
{
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*NumberOfNetworkIntfs = 0;
|
|
*NetworkIntfInstances = NULL;
|
|
|
|
if (IsListEmpty ((const LIST_ENTRY *)&mEfiRedfishDiscoverNetworkInterface)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
RestExInstance = EFI_REDFISH_DISOVER_DATA_FROM_DISCOVER_PROTOCOL (This);
|
|
|
|
//
|
|
// Check the new found network interface.
|
|
//
|
|
if (RestExInstance->NetworkInterfaceInstances != NULL) {
|
|
FreePool (RestExInstance->NetworkInterfaceInstances);
|
|
RestExInstance->NetworkInterfaceInstances = NULL;
|
|
}
|
|
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE) * mNumNetworkInterface);
|
|
if (ThisNetworkInterface == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
*NetworkIntfInstances = ThisNetworkInterface;
|
|
|
|
RestExInstance->NetworkInterfaceInstances = ThisNetworkInterface;
|
|
RestExInstance->NumberOfNetworkInterfaces = 0;
|
|
|
|
ThisNetworkInterfaceIntn = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
|
|
while (TRUE) {
|
|
// If Get Subnet Info failed then skip this interface
|
|
Status = NetworkInterfaceGetSubnetInfo (ThisNetworkInterfaceIntn, ImageHandle); // Get subnet info
|
|
if (EFI_ERROR (Status)) {
|
|
if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterfaceIntn->Entry)) {
|
|
break;
|
|
}
|
|
|
|
ThisNetworkInterfaceIntn = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterfaceIntn->Entry);
|
|
continue;
|
|
}
|
|
|
|
ThisNetworkInterface->IsIpv6 = FALSE;
|
|
if (CheckIsIpVersion6 (ThisNetworkInterfaceIntn)) {
|
|
ThisNetworkInterface->IsIpv6 = TRUE;
|
|
}
|
|
|
|
CopyMem ((VOID *)&ThisNetworkInterface->MacAddress, &ThisNetworkInterfaceIntn->MacAddress, ThisNetworkInterfaceIntn->HwAddressSize);
|
|
if (!ThisNetworkInterface->IsIpv6) {
|
|
IP4_COPY_ADDRESS (&ThisNetworkInterface->SubnetId.v4, &ThisNetworkInterfaceIntn->SubnetAddr.v4); // IPv4 subnet information.
|
|
} else {
|
|
IP6_COPY_ADDRESS (&ThisNetworkInterface->SubnetId.v6, &ThisNetworkInterfaceIntn->SubnetAddr.v6); // IPv6 subnet information in IPv6 address information.
|
|
}
|
|
|
|
ThisNetworkInterface->SubnetPrefixLength = ThisNetworkInterfaceIntn->SubnetPrefixLength;
|
|
ThisNetworkInterface->VlanId = ThisNetworkInterfaceIntn->VlanId;
|
|
RestExInstance->NumberOfNetworkInterfaces++;
|
|
if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterfaceIntn->Entry)) {
|
|
break;
|
|
}
|
|
|
|
ThisNetworkInterfaceIntn = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterfaceIntn->Entry);
|
|
ThisNetworkInterface++;
|
|
}
|
|
|
|
*NumberOfNetworkIntfs = RestExInstance->NumberOfNetworkInterfaces;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function acquires Redfish services by discovering static Redfish setting
|
|
according to Redfish Host Interface or through SSDP. Returns a list of EFI
|
|
handles in EFI_REDFISH_DISCOVERED_LIST. Each of EFI handle has corresponding
|
|
EFI REST EX instance installed on it. Each REST EX instance is a child instance which
|
|
created through EFI REST EX service protocol for communicating with specific
|
|
Redfish service.
|
|
|
|
@param[in] This EFI_REDFISH_DISCOVER_PROTOCOL instance.
|
|
@param[in] ImageHandle EFI image owns these Redfish service instances.
|
|
@param[in] TargetNetworkInterface Target network interface to do the discovery.
|
|
NULL means discover Redfish service on all network interfaces on platform.
|
|
@param[in] Flags Redfish service discover flags.
|
|
@param[in] Token EFI_REDFISH_DISCOVERED_TOKEN instance.
|
|
The memory of EFI_REDFISH_DISCOVERED_LIST and the strings in
|
|
EFI_REDFISH_DISCOVERED_INFORMATION are all allocated by Acquire()
|
|
and must be freed when caller invoke Release().
|
|
|
|
@retval EFI_SUCCESS REST EX instance of discovered Redfish services are returned.
|
|
@retval EFI_INVALID_PARAMETERS ImageHandle == NULL, Flags == 0, Token == NULL, Token->Timeout > 5,
|
|
or Token->Event == NULL.
|
|
@retval Others Fail acquire Redfish services.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RedfishServiceAcquireService (
|
|
IN EFI_REDFISH_DISCOVER_PROTOCOL *This,
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *TargetNetworkInterface,
|
|
IN EFI_REDFISH_DISCOVER_FLAG Flags,
|
|
IN EFI_REDFISH_DISCOVERED_TOKEN *Token
|
|
)
|
|
{
|
|
EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance;
|
|
EFI_STATUS Status1;
|
|
BOOLEAN NewInstance;
|
|
UINTN NumNetworkInterfaces;
|
|
UINTN NetworkInterfacesIndex;
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *TargetNetworkInterfaceInternal;
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a:Entry.\n", __func__));
|
|
|
|
//
|
|
// Validate parameters.
|
|
//
|
|
if ((ImageHandle == NULL) || (Token == NULL) || ((Flags & ~EFI_REDFISH_DISCOVER_VALIDATION) == 0)) {
|
|
DEBUG ((DEBUG_ERROR, "%a:Invalid parameters.\n", __func__));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Validate target network interface.
|
|
//
|
|
if (EFI_ERROR (ValidateTargetNetworkInterface (TargetNetworkInterface, Flags))) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (TargetNetworkInterface != NULL) {
|
|
TargetNetworkInterfaceInternal = GetTargetNetworkInterfaceInternal (TargetNetworkInterface);
|
|
if (TargetNetworkInterfaceInternal == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "%a:No network interface on platform.\n", __func__));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
NumNetworkInterfaces = 1;
|
|
} else {
|
|
TargetNetworkInterfaceInternal = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
|
|
NumNetworkInterfaces = NumberOfNetworkInterface ();
|
|
if (NumNetworkInterfaces == 0) {
|
|
DEBUG ((DEBUG_ERROR, "%a:No network interface on platform.\n", __func__));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
for (NetworkInterfacesIndex = 0; NetworkInterfacesIndex < NumNetworkInterfaces; NetworkInterfacesIndex++) {
|
|
Status1 = EFI_SUCCESS;
|
|
NewInstance = FALSE;
|
|
Instance = GetInstanceByOwner (ImageHandle, TargetNetworkInterfaceInternal, Flags & ~EFI_REDFISH_DISCOVER_VALIDATION); // Check if we can re-use previous instance.
|
|
if (Instance == NULL) {
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a:Create new EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.\n", __func__));
|
|
Instance = (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE));
|
|
if (Instance == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "%a:Memory allocation fail.\n", __func__));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
InitializeListHead (&Instance->Entry);
|
|
Instance->Owner = ImageHandle;
|
|
Instance->DiscoverFlags = Flags & ~EFI_REDFISH_DISCOVER_VALIDATION;
|
|
Instance->NetworkInterface = TargetNetworkInterfaceInternal;
|
|
//
|
|
// Get subnet information in case subnet information is not set because
|
|
// RedfishServiceGetNetworkInterfaces hasn't been called yet.
|
|
//
|
|
Status1 = NetworkInterfaceGetSubnetInfo (TargetNetworkInterfaceInternal, ImageHandle);
|
|
if (EFI_ERROR (Status1)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Get subnet information fail.\n", __func__));
|
|
FreePool (Instance);
|
|
continue;
|
|
}
|
|
|
|
NewInstance = TRUE;
|
|
}
|
|
|
|
if (TargetNetworkInterfaceInternal->StrMacAddr != NULL) {
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a:Acquire Redfish service on network interface MAC address:%s.\n", __func__, TargetNetworkInterfaceInternal->StrMacAddr));
|
|
} else {
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a:WARNING: No MAC address on this network interface.\n", __func__));
|
|
}
|
|
|
|
Instance->DiscoverToken = Token; // Always use the latest Token passed by caller.
|
|
if ((Flags & EFI_REDFISH_DISCOVER_HOST_INTERFACE) != 0) {
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a:Redfish HOST interface discovery.\n", __func__));
|
|
Instance->HostIntfValidation = FALSE;
|
|
if ((Flags & EFI_REDFISH_DISCOVER_VALIDATION) != 0) {
|
|
Instance->HostIntfValidation = TRUE;
|
|
}
|
|
|
|
Status1 = DiscoverRedfishHostInterface (Instance); // Discover Redfish service through Redfish Host Interface.
|
|
}
|
|
|
|
if ((Flags & EFI_REDFISH_DISCOVER_SSDP) != 0) {
|
|
DEBUG ((DEBUG_ERROR, "%a:Redfish service discovery through SSDP is not supported\n", __func__));
|
|
return EFI_UNSUPPORTED;
|
|
} else {
|
|
if (EFI_ERROR (Status1)) {
|
|
if (NewInstance) {
|
|
FreePool ((VOID *)Instance);
|
|
}
|
|
|
|
DEBUG ((DEBUG_ERROR, "%a:Something wrong on Redfish service discovery Status1=%r.\n", __func__, Status1));
|
|
} else {
|
|
if (NewInstance) {
|
|
InsertTailList (&mRedfishDiscoverList, &Instance->Entry);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TargetNetworkInterface == NULL) {
|
|
//
|
|
// Discover Redfish services on all of network interfaces.
|
|
//
|
|
TargetNetworkInterfaceInternal = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode (&mEfiRedfishDiscoverNetworkInterface, &TargetNetworkInterfaceInternal->Entry);
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function aborts Redfish service discovery on the given network interface.
|
|
|
|
@param[in] This EFI_REDFISH_DISCOVER_PROTOCOL instance.
|
|
@param[in] TargetNetworkInterface Target network interface to do the discovery.
|
|
|
|
@retval EFI_SUCCESS REST EX instance of discovered Redfish services are returned.
|
|
@retval Others Fail to abort Redfish service discovery.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RedfishServiceAbortAcquire (
|
|
IN EFI_REDFISH_DISCOVER_PROTOCOL *This,
|
|
IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *TargetNetworkInterface OPTIONAL
|
|
)
|
|
{
|
|
// This function is used to abort Redfish service discovery through SSDP
|
|
// on the network interface. SSDP is optionally suppoted by EFI_REDFISH_DISCOVER_PROTOCOL,
|
|
// we dont have implementation for SSDP now.
|
|
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
This function releases Redfish services found by RedfishServiceAcquire().
|
|
|
|
@param[in] This EFI_REDFISH_DISCOVER_PROTOCOL instance.
|
|
@param[in] InstanceList The Redfish service to release.
|
|
|
|
@retval EFI_SUCCESS REST EX instances of discovered Redfish are released.
|
|
@retval Others Fail to remove the entry
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RedfishServiceReleaseService (
|
|
IN EFI_REDFISH_DISCOVER_PROTOCOL *This,
|
|
IN EFI_REDFISH_DISCOVERED_LIST *InstanceList
|
|
)
|
|
{
|
|
UINTN NumService;
|
|
BOOLEAN AnyFailRelease;
|
|
EFI_REDFISH_DISCOVERED_INSTANCE *ThisRedfishInstance;
|
|
EFI_REDFISH_DISCOVERED_INTERNAL_LIST *DiscoveredRedfishInstance;
|
|
|
|
if (IsListEmpty (&mRedfishInstanceList)) {
|
|
DEBUG ((DEBUG_ERROR, "%a:No any discovered Redfish service.\n", __func__));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
AnyFailRelease = FALSE;
|
|
ThisRedfishInstance = InstanceList->RedfishInstances;
|
|
for (NumService = 0; NumService < InstanceList->NumberOfServiceFound; NumService++) {
|
|
DiscoveredRedfishInstance = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetFirstNode (&mRedfishInstanceList);
|
|
do {
|
|
if (DiscoveredRedfishInstance->Instance == ThisRedfishInstance) {
|
|
RemoveEntryList (&DiscoveredRedfishInstance->NextInstance);
|
|
if (ThisRedfishInstance->Information.Location != NULL) {
|
|
FreePool (ThisRedfishInstance->Information.Location);
|
|
}
|
|
|
|
if (ThisRedfishInstance->Information.Uuid != NULL) {
|
|
FreePool (ThisRedfishInstance->Information.Uuid);
|
|
}
|
|
|
|
if (ThisRedfishInstance->Information.Os != NULL) {
|
|
FreePool (ThisRedfishInstance->Information.Os);
|
|
}
|
|
|
|
if (ThisRedfishInstance->Information.OsVersion != NULL) {
|
|
FreePool (ThisRedfishInstance->Information.OsVersion);
|
|
}
|
|
|
|
if (ThisRedfishInstance->Information.Product != NULL) {
|
|
FreePool (ThisRedfishInstance->Information.Product);
|
|
}
|
|
|
|
if (ThisRedfishInstance->Information.ProductVer != NULL) {
|
|
FreePool (ThisRedfishInstance->Information.ProductVer);
|
|
}
|
|
|
|
FreePool ((VOID *)ThisRedfishInstance);
|
|
goto ReleaseNext;
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mRedfishInstanceList, &DiscoveredRedfishInstance->NextInstance)) {
|
|
break;
|
|
}
|
|
|
|
DiscoveredRedfishInstance = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetNextNode (&mRedfishInstanceList, &DiscoveredRedfishInstance->NextInstance);
|
|
} while (TRUE);
|
|
|
|
AnyFailRelease = TRUE;
|
|
ReleaseNext:;
|
|
//
|
|
// Release next discovered Redfish Service.
|
|
//
|
|
ThisRedfishInstance = (EFI_REDFISH_DISCOVERED_INSTANCE *)((UINT8 *)ThisRedfishInstance + sizeof (EFI_REDFISH_DISCOVERED_INSTANCE));
|
|
}
|
|
|
|
if (AnyFailRelease) {
|
|
return EFI_NOT_FOUND;
|
|
} else {
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/**
|
|
This function create an EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL for the
|
|
given network interface.
|
|
|
|
|
|
@param[in] ControllerHandle MAC address of this network interface.
|
|
@param[in] NetworkProtocolType Network protocol type.
|
|
@param[out] IsNewInstance BOOLEAN means new instance or not.
|
|
@param[out] NetworkInterface Pointer to to EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL.
|
|
|
|
@retval EFI_STATUS
|
|
**/
|
|
EFI_STATUS
|
|
CreateRedfishDiscoverNetworkInterface (
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN UINT32 NetworkProtocolType,
|
|
OUT BOOLEAN *IsNewInstance,
|
|
OUT EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL **NetworkInterface
|
|
)
|
|
{
|
|
EFI_MAC_ADDRESS MacAddress;
|
|
UINTN HwAddressSize;
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NewNetworkInterface;
|
|
|
|
NetLibGetMacAddress (ControllerHandle, &MacAddress, &HwAddressSize);
|
|
NewNetworkInterface = NULL;
|
|
*IsNewInstance = TRUE;
|
|
if (!IsListEmpty ((const LIST_ENTRY *)&mEfiRedfishDiscoverNetworkInterface)) {
|
|
//
|
|
// Check if this instance already exist.
|
|
//
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
|
|
if (ThisNetworkInterface != NULL) {
|
|
while (TRUE) {
|
|
if ((CompareMem ((CONST VOID *)&ThisNetworkInterface->MacAddress.Addr, (CONST VOID *)&MacAddress.Addr, HwAddressSize) == 0) &&
|
|
(ThisNetworkInterface->NetworkProtocolType == NetworkProtocolType))
|
|
{
|
|
NewNetworkInterface = ThisNetworkInterface;
|
|
*IsNewInstance = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
|
|
NewNetworkInterface = NULL;
|
|
break;
|
|
}
|
|
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NewNetworkInterface == NULL) {
|
|
//
|
|
// Create a new instance.
|
|
//
|
|
NewNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL));
|
|
if (NewNetworkInterface == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
NewNetworkInterface->HwAddressSize = HwAddressSize;
|
|
CopyMem (&NewNetworkInterface->MacAddress.Addr, &MacAddress.Addr, NewNetworkInterface->HwAddressSize);
|
|
NetLibGetMacString (ControllerHandle, NULL, &NewNetworkInterface->StrMacAddr);
|
|
NewNetworkInterface->VlanId = NetLibGetVlanId (ControllerHandle);
|
|
}
|
|
|
|
*NetworkInterface = NewNetworkInterface;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function destroy network interface
|
|
|
|
|
|
@param[in] ThisNetworkInterface EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance.
|
|
|
|
@retval EFI_STATUS
|
|
**/
|
|
EFI_STATUS
|
|
DestroyRedfishNetworkInterface (
|
|
IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = gBS->UninstallProtocolInterface (
|
|
ThisNetworkInterface->OpenDriverControllerHandle,
|
|
mRequiredProtocol[ThisNetworkInterface->NetworkProtocolType].DiscoveredProtocolGuid,
|
|
&ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolDiscoverId
|
|
);
|
|
RemoveEntryList (&ThisNetworkInterface->Entry);
|
|
mNumNetworkInterface--;
|
|
FreePool (ThisNetworkInterface);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Tests to see if the required protocols are provided on the given
|
|
controller handle.
|
|
|
|
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param[in] ControllerHandle The handle of the controller to test. This handle
|
|
must support a protocol interface that supplies
|
|
an I/O abstraction to the driver.
|
|
@retval EFI_SUCCESS One of required protocol is found.
|
|
@retval EFI_UNSUPPORTED None of required protocol is found.
|
|
**/
|
|
EFI_STATUS
|
|
TestForRequiredProtocols (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle
|
|
)
|
|
{
|
|
UINT32 *Id;
|
|
UINTN Index;
|
|
EFI_STATUS Status;
|
|
UINTN ListCount;
|
|
|
|
ListCount = (sizeof (mRequiredProtocol) / sizeof (REDFISH_DISCOVER_REQUIRED_PROTOCOL));
|
|
for (Index = 0; Index < ListCount; Index++) {
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
mRequiredProtocol[Index].RequiredServiceBindingProtocolGuid,
|
|
NULL,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
mRequiredProtocol[Index].DiscoveredProtocolGuid,
|
|
(VOID **)&Id,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
// Already installed
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: all required protocols are found on this controller handle: %p.\n", __func__, ControllerHandle));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Build up network interface and create corresponding service through the given
|
|
controller handle.
|
|
|
|
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param[in] ControllerHandle The handle of the controller to test. This handle
|
|
must support a protocol interface that supplies
|
|
an I/O abstraction to the driver.
|
|
@retval EFI_SUCCESS One of required protocol is found.
|
|
@retval EFI_UNSUPPORTED None of required protocol is found.
|
|
@retval EFI_UNSUPPORTED Failed to build up network interface.
|
|
**/
|
|
EFI_STATUS
|
|
BuildupNetworkInterface (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle
|
|
)
|
|
{
|
|
UINT32 *Id;
|
|
UINT32 Index;
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NetworkInterface;
|
|
BOOLEAN IsNew;
|
|
EFI_STATUS Status;
|
|
VOID *TempInterface;
|
|
VOID **Interface;
|
|
UINT32 *ProtocolDiscoverIdPtr;
|
|
EFI_HANDLE OpenDriverAgentHandle;
|
|
EFI_HANDLE OpenDriverControllerHandle;
|
|
EFI_HANDLE *HandleOfProtocolInterfacePtr;
|
|
EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *RestExInstance;
|
|
EFI_TPL OldTpl;
|
|
BOOLEAN NewNetworkInterfaceInstalled;
|
|
UINT8 IpType;
|
|
UINTN ListCount;
|
|
|
|
ListCount = (sizeof (mRequiredProtocol) / sizeof (REDFISH_DISCOVER_REQUIRED_PROTOCOL));
|
|
NewNetworkInterfaceInstalled = FALSE;
|
|
Index = 0;
|
|
|
|
// Get IP Type to filter out unnecessary network protocol if possible
|
|
IpType = GetHiIpProtocolType ();
|
|
|
|
for (Index = 0; Index < ListCount; Index++) {
|
|
// Check IP Type and skip an unnecessary network protocol if does not match
|
|
if (FilterProtocol (mRequiredProtocol[Index].ProtocolType, IpType)) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBS->OpenProtocol (
|
|
// Already in list?
|
|
ControllerHandle,
|
|
mRequiredProtocol[Index].DiscoveredProtocolGuid,
|
|
(VOID **)&Id,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
mRequiredProtocol[Index].RequiredServiceBindingProtocolGuid,
|
|
&TempInterface,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
if (mRequiredProtocol[Index].ProtocolType != ProtocolTypeRestEx) {
|
|
OldTpl = gBS->RaiseTPL (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
|
|
Status = CreateRedfishDiscoverNetworkInterface (ControllerHandle, mRequiredProtocol[Index].ProtocolType, &IsNew, &NetworkInterface);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
}
|
|
|
|
NetworkInterface->NetworkProtocolType = mRequiredProtocol[Index].ProtocolType;
|
|
NetworkInterface->OpenDriverAgentHandle = This->DriverBindingHandle;
|
|
NetworkInterface->OpenDriverControllerHandle = ControllerHandle;
|
|
CopyGuid (&NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolGuid, mRequiredProtocol[Index].RequiredProtocolGuid);
|
|
CopyGuid (&NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolServiceGuid, mRequiredProtocol[Index].RequiredServiceBindingProtocolGuid);
|
|
ProtocolDiscoverIdPtr = &NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolDiscoverId;
|
|
OpenDriverAgentHandle = NetworkInterface->OpenDriverAgentHandle;
|
|
OpenDriverControllerHandle = NetworkInterface->OpenDriverControllerHandle;
|
|
HandleOfProtocolInterfacePtr = &NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle;
|
|
Interface = &NetworkInterface->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
|
|
NewNetworkInterfaceInstalled = TRUE;
|
|
if (IsNew) {
|
|
InsertTailList (&mEfiRedfishDiscoverNetworkInterface, &NetworkInterface->Entry);
|
|
mNumNetworkInterface++;
|
|
}
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
} else {
|
|
// Record REST_EX instance. REST_EX is created when client asks for Redfish service discovery.
|
|
// Redfish Service Discover protocol will match REST EX to the corresponding EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
|
|
// when discovery.
|
|
|
|
RestExInstance = (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL));
|
|
if (RestExInstance == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
RestExInstance->OpenDriverAgentHandle = This->DriverBindingHandle;
|
|
RestExInstance->OpenDriverControllerHandle = ControllerHandle;
|
|
RestExInstance->RestExControllerHandle = ControllerHandle;
|
|
InitializeListHead (&RestExInstance->Entry);
|
|
InsertTailList (&mEfiRedfishDiscoverRestExInstance, &RestExInstance->Entry);
|
|
mNumRestExInstance++;
|
|
ProtocolDiscoverIdPtr = &RestExInstance->RestExId;
|
|
OpenDriverAgentHandle = RestExInstance->OpenDriverAgentHandle;
|
|
OpenDriverControllerHandle = RestExInstance->OpenDriverControllerHandle;
|
|
HandleOfProtocolInterfacePtr = &RestExInstance->RestExChildHandle;
|
|
Interface = (VOID **)&RestExInstance->RestExProtocolInterface;
|
|
}
|
|
|
|
Status = gBS->InstallProtocolInterface (
|
|
&ControllerHandle,
|
|
mRequiredProtocol[Index].DiscoveredProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
ProtocolDiscoverIdPtr
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Create service binding child and open it BY_DRIVER.
|
|
//
|
|
Status = NetLibCreateServiceChild (
|
|
ControllerHandle,
|
|
This->ImageHandle,
|
|
mRequiredProtocol[Index].RequiredServiceBindingProtocolGuid,
|
|
HandleOfProtocolInterfacePtr
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gBS->OpenProtocol (
|
|
*HandleOfProtocolInterfacePtr,
|
|
mRequiredProtocol[Index].RequiredProtocolGuid,
|
|
Interface,
|
|
OpenDriverAgentHandle,
|
|
OpenDriverControllerHandle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
if ((mRequiredProtocol[Index].ProtocolType == ProtocolTypeRestEx)) {
|
|
// Install Redfish Discover Protocol when EFI REST EX protocol is discovered.
|
|
// This ensures EFI REST EX is ready while the consumer of EFI_REDFISH_DISCOVER_PROTOCOL
|
|
// acquires Redfish service over network interface.
|
|
|
|
if (!NewNetworkInterfaceInstalled) {
|
|
NetworkInterface = GetTargetNetworkInterfaceInternalByController (ControllerHandle);
|
|
if (NetworkInterface == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Can't find network interface by ControllerHandle\n", __func__));
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
NewNetworkInterfaceInstalled = FALSE;
|
|
NetworkInterface->EfiRedfishDiscoverProtocolHandle = NULL;
|
|
|
|
RestExInstance->Signature = EFI_REDFISH_DISCOVER_DATA_SIGNATURE;
|
|
|
|
RestExInstance->RedfishDiscoverProtocol.GetNetworkInterfaceList = RedfishServiceGetNetworkInterface;
|
|
RestExInstance->RedfishDiscoverProtocol.AcquireRedfishService = RedfishServiceAcquireService;
|
|
RestExInstance->RedfishDiscoverProtocol.AbortAcquireRedfishService = RedfishServiceAbortAcquire;
|
|
RestExInstance->RedfishDiscoverProtocol.ReleaseRedfishService = RedfishServiceReleaseService;
|
|
|
|
Status = gBS->InstallProtocolInterface (
|
|
&NetworkInterface->EfiRedfishDiscoverProtocolHandle,
|
|
&gEfiRedfishDiscoverProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
(VOID *)&RestExInstance->RedfishDiscoverProtocol
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Fail to install EFI_REDFISH_DISCOVER_PROTOCOL\n", __func__));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Not REST EX, continue with next\n", __func__));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
/**
|
|
Close the protocol opened for Redfish discovery. This function also destroy
|
|
the network services.
|
|
|
|
@param[in] ThisBindingProtocol A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param[in] ControllerHandle The handle of the controller to test. This handle
|
|
must support a protocol interface that supplies
|
|
an I/O abstraction to the driver.
|
|
@param[in] ThisRequiredProtocol Pointer to the instance of REDFISH_DISCOVER_REQUIRED_PROTOCOL.
|
|
@param[in] DriverAgentHandle Driver agent handle which used to open protocol earlier.
|
|
@param[in] DriverControllerHandle Driver controller handle which used to open protocol earlier.
|
|
|
|
@retval EFI_SUCCESS Protocol is closed successfully.
|
|
@retval Others Protocol is closed unsuccessfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CloseProtocolService (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *ThisBindingProtocol,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN REDFISH_DISCOVER_REQUIRED_PROTOCOL *ThisRequiredProtocol,
|
|
IN EFI_HANDLE DriverAgentHandle,
|
|
IN EFI_HANDLE DriverControllerHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = gBS->CloseProtocol (
|
|
ControllerHandle,
|
|
ThisRequiredProtocol->RequiredProtocolGuid,
|
|
DriverAgentHandle,
|
|
DriverControllerHandle
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
NetLibDestroyServiceChild (
|
|
ControllerHandle,
|
|
ThisBindingProtocol->ImageHandle,
|
|
ThisRequiredProtocol->RequiredServiceBindingProtocolGuid,
|
|
ControllerHandle
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Stop the services on network interface.
|
|
|
|
@param[in] ThisBindingProtocol A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param[in] ControllerHandle The handle of the controller to test. This handle
|
|
must support a protocol interface that supplies
|
|
an I/O abstraction to the driver.
|
|
@retval EFI_SUCCESS One of required protocol is found.
|
|
@retval Others Failed to stop the services on network interface.
|
|
**/
|
|
EFI_STATUS
|
|
StopServiceOnNetworkInterface (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *ThisBindingProtocol,
|
|
IN EFI_HANDLE ControllerHandle
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
EFI_STATUS Status;
|
|
VOID *Interface;
|
|
EFI_TPL OldTpl;
|
|
EFI_HANDLE DiscoverProtocolHandle;
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
|
|
EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *RestExInstance;
|
|
EFI_REDFISH_DISCOVER_PROTOCOL *RedfishDiscoverProtocol;
|
|
|
|
for (Index = 0; Index < (sizeof (mRequiredProtocol) / sizeof (REDFISH_DISCOVER_REQUIRED_PROTOCOL)); Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
ControllerHandle,
|
|
mRequiredProtocol[Index].RequiredProtocolGuid,
|
|
(VOID **)&Interface
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
if (mRequiredProtocol[Index].ProtocolType != ProtocolTypeRestEx) {
|
|
if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
OldTpl = gBS->RaiseTPL (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
|
|
while (TRUE) {
|
|
if (ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle == ControllerHandle) {
|
|
DiscoverProtocolHandle = ThisNetworkInterface->EfiRedfishDiscoverProtocolHandle;
|
|
//
|
|
// Close protocol and destroy service.
|
|
//
|
|
Status = CloseProtocolService (
|
|
ThisBindingProtocol,
|
|
ControllerHandle,
|
|
&mRequiredProtocol[Index],
|
|
ThisNetworkInterface->OpenDriverAgentHandle,
|
|
ThisNetworkInterface->OpenDriverControllerHandle
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = DestroyRedfishNetworkInterface (ThisNetworkInterface);
|
|
}
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
//
|
|
// Disconnect EFI Redfish discover driver controller to notify the
|
|
// client which uses .EFI Redfish discover protocol.
|
|
//
|
|
if (DiscoverProtocolHandle != NULL) {
|
|
Status = gBS->HandleProtocol (
|
|
DiscoverProtocolHandle,
|
|
&gEfiRedfishDiscoverProtocolGuid,
|
|
(VOID **)&RedfishDiscoverProtocol
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
RestExInstance = EFI_REDFISH_DISOVER_DATA_FROM_DISCOVER_PROTOCOL (RedfishDiscoverProtocol);
|
|
//
|
|
// Stop Redfish service discovery.
|
|
//
|
|
RedfishDiscoverProtocol->AbortAcquireRedfishService (
|
|
RedfishDiscoverProtocol,
|
|
RestExInstance->NetworkInterfaceInstances
|
|
);
|
|
|
|
gBS->DisconnectController (DiscoverProtocolHandle, NULL, NULL);
|
|
Status = gBS->UninstallProtocolInterface (
|
|
DiscoverProtocolHandle,
|
|
&gEfiRedfishDiscoverProtocolGuid,
|
|
(VOID *)&RestExInstance->RedfishDiscoverProtocol
|
|
);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
|
|
break;
|
|
}
|
|
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
|
|
}
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
} else {
|
|
if (IsListEmpty (&mEfiRedfishDiscoverRestExInstance)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
OldTpl = gBS->RaiseTPL (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
|
|
RestExInstance = (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverRestExInstance);
|
|
while (TRUE) {
|
|
if (RestExInstance->RestExChildHandle == ControllerHandle) {
|
|
Status = CloseProtocolService (
|
|
// Close REST_EX protocol.
|
|
ThisBindingProtocol,
|
|
ControllerHandle,
|
|
&mRequiredProtocol[Index],
|
|
RestExInstance->OpenDriverAgentHandle,
|
|
RestExInstance->OpenDriverControllerHandle
|
|
);
|
|
RemoveEntryList (&RestExInstance->Entry);
|
|
FreePool ((VOID *)RestExInstance);
|
|
mNumRestExInstance--;
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mEfiRedfishDiscoverRestExInstance, &RestExInstance->Entry)) {
|
|
break;
|
|
}
|
|
|
|
RestExInstance = (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)GetNextNode (&mEfiRedfishDiscoverRestExInstance, &RestExInstance->Entry);
|
|
}
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
}
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Tests to see if this driver supports a given controller. If a child device is provided,
|
|
it further tests to see if this driver supports creating a handle for the specified child device.
|
|
|
|
This function checks to see if the driver specified by This supports the device specified by
|
|
ControllerHandle. Drivers will typically use the device path attached to
|
|
ControllerHandle and/or the services from the bus I/O abstraction attached to
|
|
ControllerHandle to determine if the driver supports ControllerHandle. This function
|
|
may be called many times during platform initialization. In order to reduce boot times, the tests
|
|
performed by this function must be very small, and take as little time as possible to execute. This
|
|
function must not change the state of any hardware devices, and this function must be aware that the
|
|
device specified by ControllerHandle may already be managed by the same driver or a
|
|
different driver. This function must match its calls to AllocatePages() with FreePages(),
|
|
AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
|
|
Because ControllerHandle may have been previously started by the same driver, if a protocol is
|
|
already in the opened state, then it must not be closed with CloseProtocol(). This is required
|
|
to guarantee the state of ControllerHandle is not modified by this function.
|
|
|
|
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param[in] ControllerHandle The handle of the controller to test. This handle
|
|
must support a protocol interface that supplies
|
|
an I/O abstraction to the driver.
|
|
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
|
|
parameter is ignored by device drivers, and is optional for bus
|
|
drivers. For bus drivers, if this parameter is not NULL, then
|
|
the bus driver must determine if the bus controller specified
|
|
by ControllerHandle and the child controller specified
|
|
by RemainingDevicePath are both supported by this
|
|
bus driver.
|
|
|
|
@retval EFI_SUCCESS The device specified by ControllerHandle and
|
|
RemainingDevicePath is supported by the driver specified by This.
|
|
@retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
|
|
RemainingDevicePath is already being managed by the driver
|
|
specified by This.
|
|
@retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
|
|
RemainingDevicePath is already being managed by a different
|
|
driver or an application that requires exclusive access.
|
|
Currently not implemented.
|
|
@retval EFI_UNSUPPORTED The device specified by ControllerHandle and
|
|
RemainingDevicePath is not supported by the driver specified by This.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RedfishDiscoverDriverBindingSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
|
)
|
|
{
|
|
return TestForRequiredProtocols (This, ControllerHandle);
|
|
}
|
|
|
|
/**
|
|
Starts a device controller or a bus controller.
|
|
|
|
The Start() function is designed to be invoked from the EFI boot service ConnectController().
|
|
As a result, much of the error checking on the parameters to Start() has been moved into this
|
|
common boot service. It is legal to call Start() from other locations,
|
|
but the following calling restrictions must be followed, or the system behavior will not be deterministic.
|
|
1. ControllerHandle must be a valid EFI_HANDLE.
|
|
2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
|
|
EFI_DEVICE_PATH_PROTOCOL.
|
|
3. Prior to calling Start(), the Supported() function for the driver specified by This must
|
|
have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
|
|
|
|
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param[in] ControllerHandle The handle of the controller to start. This handle
|
|
must support a protocol interface that supplies
|
|
an I/O abstraction to the driver.
|
|
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
|
|
parameter is ignored by device drivers, and is optional for bus
|
|
drivers. For a bus driver, if this parameter is NULL, then handles
|
|
for all the children of Controller are created by this driver.
|
|
If this parameter is not NULL and the first Device Path Node is
|
|
not the End of Device Path Node, then only the handle for the
|
|
child device specified by the first Device Path Node of
|
|
RemainingDevicePath is created by this driver.
|
|
If the first Device Path Node of RemainingDevicePath is
|
|
the End of Device Path Node, no child handle is created by this
|
|
driver.
|
|
|
|
@retval EFI_SUCCESS The device was started.
|
|
@retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
|
|
@retval Others The driver failed to start the device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RedfishDiscoverDriverBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
|
)
|
|
{
|
|
return BuildupNetworkInterface (This, ControllerHandle);
|
|
}
|
|
|
|
/**
|
|
Stops a device controller or a bus controller.
|
|
|
|
The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
|
|
As a result, much of the error checking on the parameters to Stop() has been moved
|
|
into this common boot service. It is legal to call Stop() from other locations,
|
|
but the following calling restrictions must be followed, or the system behavior will not be deterministic.
|
|
1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
|
|
same driver's Start() function.
|
|
2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
|
|
EFI_HANDLE. In addition, all of these handles must have been created in this driver's
|
|
Start() function, and the Start() function must have called OpenProtocol() on
|
|
ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
|
|
|
|
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param[in] ControllerHandle A handle to the device being stopped. The handle must
|
|
support a bus specific I/O protocol for the driver
|
|
to use to stop the device.
|
|
@param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
|
|
@param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
|
|
if NumberOfChildren is 0.
|
|
|
|
@retval EFI_SUCCESS The device was stopped.
|
|
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RedfishDiscoverDriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
|
|
)
|
|
{
|
|
return StopServiceOnNetworkInterface (This, ControllerHandle);
|
|
}
|
|
|
|
EFI_DRIVER_BINDING_PROTOCOL gRedfishDiscoverDriverBinding = {
|
|
RedfishDiscoverDriverBindingSupported,
|
|
RedfishDiscoverDriverBindingStart,
|
|
RedfishDiscoverDriverBindingStop,
|
|
REDFISH_DISCOVER_VERSION,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
/**
|
|
This is the declaration of an EFI image entry point.
|
|
|
|
@param ImageHandle The firmware allocated handle for the UEFI image.
|
|
@param SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The operation completed successfully.
|
|
@retval Others An unexpected error occurred.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RedfishDiscoverEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_SUCCESS;
|
|
InitializeListHead (&mRedfishDiscoverList);
|
|
InitializeListHead (&mRedfishInstanceList);
|
|
InitializeListHead (&mEfiRedfishDiscoverNetworkInterface);
|
|
InitializeListHead (&mEfiRedfishDiscoverRestExInstance);
|
|
//
|
|
// Install binding protocol to obtain UDP and REST EX protocol.
|
|
//
|
|
Status = EfiLibInstallDriverBindingComponentName2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&gRedfishDiscoverDriverBinding,
|
|
ImageHandle,
|
|
&gRedfishDiscoverComponentName,
|
|
&gRedfishDiscoverComponentName2
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This is the unload handle for Redfish discover module.
|
|
|
|
Disconnect the driver specified by ImageHandle from all the devices in the handle database.
|
|
Uninstall all the protocols installed in the driver entry point.
|
|
|
|
@param[in] ImageHandle The drivers' driver image.
|
|
|
|
@retval EFI_SUCCESS The image is unloaded.
|
|
@retval Others Failed to unload the image.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RedfishDiscoverUnload (
|
|
IN EFI_HANDLE ImageHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
|
|
|
|
Status = EFI_SUCCESS;
|
|
// Destroy all network interfaces found by EFI Redfish Discover driver and
|
|
// stop services created for Redfish Discover.
|
|
|
|
while (!IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
|
|
ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
|
|
StopServiceOnNetworkInterface (&gRedfishDiscoverDriverBinding, ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle);
|
|
}
|
|
|
|
return Status;
|
|
}
|