/** @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> | |
Copyright (c) 2023, Mike Maslenkin <mike.maslenkin@gmail.com> <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; | |
} | |
/** | |
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)) { | |
DEBUG ((DEBUG_ERROR, "%a: RedfishGetHostInterfaceProtocolData is failed.\n", __func__)); | |
return Status; | |
} else { | |
// 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) { | |
DEBUG ((DEBUG_ERROR, "%a: MAC address is not matched.\n", __func__)); | |
DEBUG (( | |
DEBUG_ERROR, | |
" NetworkInterface: %02x %02x %02x %02x %02x %02x.\n", | |
Instance->NetworkInterface->MacAddress.Addr[0], | |
Instance->NetworkInterface->MacAddress.Addr[1], | |
Instance->NetworkInterface->MacAddress.Addr[2], | |
Instance->NetworkInterface->MacAddress.Addr[3], | |
Instance->NetworkInterface->MacAddress.Addr[4], | |
Instance->NetworkInterface->MacAddress.Addr[5] | |
)); | |
DEBUG (( | |
DEBUG_ERROR, | |
" Redfish Host interface: %02x %02x %02x %02x %02x %02x.\n", | |
DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.MacAddress[0], | |
DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.MacAddress[1], | |
DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.MacAddress[2], | |
DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.MacAddress[3], | |
DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.MacAddress[4], | |
DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.MacAddress[5] | |
)); | |
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; | |
DEBUG ((DEBUG_MANAGEABILITY, "Redfish service port: 443\n")); | |
} else { | |
DEBUG ((DEBUG_MANAGEABILITY, "Redfish service port: 80\n")); | |
} | |
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 releases particular strings into the structure instance. | |
@param[in] Information EFI_REDFISH_DISCOVERED_INFORMATION | |
**/ | |
STATIC | |
VOID | |
FreeInformationData ( | |
IN EFI_REDFISH_DISCOVERED_INFORMATION *Information | |
) | |
{ | |
if (Information->Location != NULL) { | |
FreePool (Information->Location); | |
Information->Location = NULL; | |
} | |
if (Information->Uuid != NULL) { | |
FreePool (Information->Uuid); | |
Information->Uuid = NULL; | |
} | |
if (Information->Os != NULL) { | |
FreePool (Information->Os); | |
Information->Os = NULL; | |
} | |
if (Information->OsVersion != NULL) { | |
FreePool (Information->OsVersion); | |
Information->OsVersion = NULL; | |
} | |
if (Information->Product != NULL) { | |
FreePool (Information->Product); | |
Information->Product = NULL; | |
} | |
if (Information->ProductVer != NULL) { | |
FreePool (Information->ProductVer); | |
Information->ProductVer = NULL; | |
} | |
} | |
/** | |
The function initializes particular strings into the structure instance. | |
@param[in] Information EFI_REDFISH_DISCOVERED_INFORMATION | |
@param[in] IsIpv6 Flag indicating IP version 6 protocol is used | |
@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. | |
**/ | |
STATIC | |
VOID | |
InitInformationData ( | |
IN EFI_REDFISH_DISCOVERED_INFORMATION *Information, | |
IN BOOLEAN IsIpv6, | |
IN UINTN *RedfishVersion OPTIONAL, | |
IN CONST CHAR8 *RedfishLocation OPTIONAL, | |
IN CONST CHAR8 *Uuid OPTIONAL, | |
IN CONST CHAR8 *Os OPTIONAL, | |
IN CONST CHAR8 *OsVer OPTIONAL, | |
IN CONST CHAR8 *Product OPTIONAL, | |
IN CONST CHAR8 *ProductVer OPTIONAL | |
) | |
{ | |
UINTN AllocationSize; | |
if (RedfishVersion != NULL) { | |
Information->RedfishVersion = *RedfishVersion; | |
DEBUG ((DEBUG_MANAGEABILITY, "Redfish service version: %d.\n", Information->RedfishVersion)); | |
} | |
if (RedfishLocation != NULL) { | |
AllocationSize = AsciiStrSize (RedfishLocation) * sizeof (CHAR16); | |
if (IsIpv6) { | |
AllocationSize += 2 * sizeof (CHAR16); // take into account '[' and ']' | |
} | |
Information->Location = AllocatePool (AllocationSize); | |
if (Information->Location != NULL) { | |
if (IsIpv6) { | |
UnicodeSPrintAsciiFormat (Information->Location, AllocationSize, "[%a]", RedfishLocation); | |
} else { | |
AsciiStrToUnicodeStrS (RedfishLocation, Information->Location, AllocationSize); | |
} | |
DEBUG ((DEBUG_MANAGEABILITY, "Redfish service location: %s.\n", Information->Location)); | |
} else { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Can not allocate memory for Redfish service location: %a.\n", | |
__func__, | |
RedfishLocation | |
)); | |
} | |
} | |
if (Uuid != NULL) { | |
AllocationSize = AsciiStrSize (Uuid) * sizeof (CHAR16); | |
Information->Uuid = AllocatePool (AllocationSize); | |
if (Information->Uuid != NULL) { | |
AsciiStrToUnicodeStrS (Uuid, Information->Uuid, AllocationSize); | |
DEBUG ((DEBUG_MANAGEABILITY, "Service UUID: %s.\n", Information->Uuid)); | |
} else { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Can not allocate memory for Service UUID: %a.\n", | |
__func__, | |
Uuid | |
)); | |
} | |
} | |
if (Os != NULL) { | |
AllocationSize = AsciiStrSize (Os) * sizeof (CHAR16); | |
Information->Os = AllocatePool (AllocationSize); | |
if (Information->Os != NULL) { | |
AsciiStrToUnicodeStrS (Os, Information->Os, AllocationSize); | |
} else { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Can not allocate memory for Redfish service OS: %a.\n", | |
__func__, | |
Os | |
)); | |
} | |
} | |
if (OsVer != NULL) { | |
AllocationSize = AsciiStrSize (OsVer) * sizeof (CHAR16); | |
Information->OsVersion = AllocatePool (AllocationSize); | |
if (Information->OsVersion != NULL) { | |
AsciiStrToUnicodeStrS (OsVer, Information->OsVersion, AllocationSize); | |
DEBUG (( | |
DEBUG_MANAGEABILITY, | |
"Redfish service OS: %s, Version:%s.\n", | |
Information->Os, | |
Information->OsVersion | |
)); | |
} else { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Can not allocate memory for Redfish OS Version:%a.\n", | |
__func__, | |
OsVer | |
)); | |
} | |
} | |
if (Product != NULL) { | |
AllocationSize = AsciiStrSize (Product) * sizeof (CHAR16); | |
Information->Product = AllocatePool (AllocationSize); | |
if (Information->Product != NULL) { | |
AsciiStrToUnicodeStrS (Product, Information->Product, AllocationSize); | |
} else { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Can not allocate memory for Redfish service product: %a.\n", | |
__func__, | |
Product | |
)); | |
} | |
} | |
if (ProductVer != NULL) { | |
AllocationSize = AsciiStrSize (ProductVer) * sizeof (CHAR16); | |
Information->ProductVer = AllocatePool (AllocationSize); | |
if (Information->ProductVer != NULL) { | |
AsciiStrToUnicodeStrS (ProductVer, Information->ProductVer, AllocationSize); | |
DEBUG (( | |
DEBUG_MANAGEABILITY, | |
"Redfish service product: %s, Version:%s.\n", | |
Information->Product, | |
Information->ProductVer | |
)); | |
} else { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Can not allocate memory for Redfish service product Version: %a.\n", | |
__func__, | |
ProductVer | |
)); | |
} | |
} | |
} | |
/** | |
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 (Char16Uuid != NULL) { | |
FreePool (Char16Uuid); | |
} | |
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; | |
} | |
} else { | |
FreeInformationData (&DiscoveredInstance->Information); | |
} | |
DEBUG ((DEBUG_MANAGEABILITY, "*** Redfish Service Information ***\n")); | |
DiscoveredInstance->Information.UseHttps = UseHttps; | |
InitInformationData ( | |
&DiscoveredInstance->Information, | |
CheckIsIpVersion6 (NetworkInterface), | |
RedfishVersion, | |
RedfishLocation, | |
Uuid, | |
Os, | |
OsVer, | |
Product, | |
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")); | |
} | |
} | |
} | |
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 is not configured..\n", __func__)); | |
DeleteRestEx = TRUE; | |
goto EXIT_FREE_ALL; | |
} else { | |
DEBUG ((DEBUG_MANAGEABILITY, "%a: REST EX is configured..\n", __func__)); | |
} | |
// | |
// 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; | |
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry.\n", __func__)); | |
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) { | |
ThisNetworkInterface->IsIpv6 = FALSE; | |
if (CheckIsIpVersion6 (ThisNetworkInterfaceIntn)) { | |
ThisNetworkInterface->IsIpv6 = TRUE; | |
} | |
CopyMem ((VOID *)&ThisNetworkInterface->MacAddress, &ThisNetworkInterfaceIntn->MacAddress, ThisNetworkInterfaceIntn->HwAddressSize); | |
// | |
// If Get Subnet Info failed then skip this interface | |
// | |
Status = NetworkInterfaceGetSubnetInfo (ThisNetworkInterfaceIntn, ImageHandle); // Get subnet info | |
if (!EFI_ERROR (Status)) { | |
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)) { | |
// | |
// Get subnet information could be failed for EFI_REDFISH_DISCOVER_HOST_INTERFACE case. | |
// We will configure network in AddAndSignalNewRedfishService. So don't skip this | |
// target network interface. | |
// | |
if ((Flags & EFI_REDFISH_DISCOVER_HOST_INTERFACE) == 0) { | |
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 | |
) | |
{ | |
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry.\n", __func__)); | |
// 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; | |
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry.\n", __func__)); | |
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); | |
FreeInformationData (&ThisRedfishInstance->Information); | |
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; | |
UINTN ListCount; | |
ListCount = (sizeof (mRequiredProtocol) / sizeof (REDFISH_DISCOVER_REQUIRED_PROTOCOL)); | |
NewNetworkInterfaceInstalled = FALSE; | |
Index = 0; | |
for (Index = 0; Index < ListCount; Index++) { | |
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 | |
) | |
{ | |
DEBUG ((DEBUG_MANAGEABILITY, "%a:Entry.\n", __func__)); | |
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; | |
} |