mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-31 01:24:12 +02:00
This patch replaces call of IpmiSubmitCommand() issued REDFISH_IPMI_BOOTSTRAP_CREDENTIAL_ENABLE IPMI command to check whether bootstrap credential support enabled or not. The problem is that in accordance with IPMI spec while handling such command BMC creates bootstrap account. The credentials of this account is returned as a response. Obviously in this code the response is not used. From the other side there is an implementation of EDKII_REDFISH_CREDENTIAL_PROTOCOL exists and used by RedfishPlatformCredentialIpmiLib. By design RedfishPlatformCredentialIpmiLib keeps returned bootstrap credentials and uses it later. So all services using EDKII_REDFISH_CREDENTIAL_PROTOCOL instance operates with a same credentials. Current design of PlatformHostInterfaceBmcUsbNicLib leads to creation of two bootstrap accounts on BMC side. This is on nesseccary and one account is not used at all. Using EDKII_REDFISH_CREDENTIAL_PROTOCOL prevents from creating useless bootstrap account on BMC side. Signed-off-by: Mike Maslenkin <mike.maslenkin@gmail.com>
1369 lines
52 KiB
C
1369 lines
52 KiB
C
/** @file
|
|
Source file to provide the platform Redfish Host Interface information
|
|
of USB NIC Device exposed by BMC.
|
|
|
|
Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "PlatformHostInterfaceBmcUsbNicLib.h"
|
|
|
|
static EFI_GUID mPlatformHostInterfaceBmcUsbNicReadinessGuid =
|
|
BMC_USB_NIC_HOST_INTERFASCE_READINESS_GUID;
|
|
static EFI_EVENT mPlatformHostInterfaceSnpEvent = NULL;
|
|
static VOID *mPlatformHostInterfaceSnpRegistration = NULL;
|
|
|
|
static LIST_ENTRY mBmcUsbNic;
|
|
static LIST_ENTRY mBmcIpmiLan;
|
|
|
|
/**
|
|
Probe if the system supports Redfish Host Interface Credentail
|
|
Bootstrapping.
|
|
|
|
@retval TRUE Yes, it is supported.
|
|
FALSE No, it is not supported.
|
|
|
|
**/
|
|
BOOLEAN
|
|
ProbeRedfishCredentialBootstrap (
|
|
VOID
|
|
)
|
|
{
|
|
EDKII_REDFISH_AUTH_METHOD AuthMethod;
|
|
EDKII_REDFISH_CREDENTIAL2_PROTOCOL *CredentialProtocol;
|
|
CHAR8 *UserName;
|
|
CHAR8 *Password;
|
|
BOOLEAN ReturnBool;
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry\n", __func__));
|
|
|
|
ReturnBool = FALSE;
|
|
//
|
|
// Locate HII credential protocol.
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEdkIIRedfishCredential2ProtocolGuid,
|
|
NULL,
|
|
(VOID **)&CredentialProtocol
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT_EFI_ERROR (Status);
|
|
return FALSE;
|
|
}
|
|
|
|
Status = CredentialProtocol->GetAuthInfo (
|
|
CredentialProtocol,
|
|
&AuthMethod,
|
|
&UserName,
|
|
&Password
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
ZeroMem (Password, AsciiStrSize (Password));
|
|
FreePool (Password);
|
|
ZeroMem (UserName, AsciiStrSize (UserName));
|
|
FreePool (UserName);
|
|
ReturnBool = TRUE;
|
|
} else {
|
|
if (Status == EFI_ACCESS_DENIED) {
|
|
// bootstrap credential support was disabled
|
|
ReturnBool = TRUE;
|
|
}
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_REDFISH_HOST_INTERFACE,
|
|
" Redfish Credential Bootstrapping is %a\n",
|
|
ReturnBool ? "supported" : "not supported"
|
|
));
|
|
return ReturnBool;
|
|
}
|
|
|
|
/**
|
|
Get platform Redfish host interface device descriptor.
|
|
|
|
@param[in] DeviceType Pointer to retrieve device type.
|
|
@param[out] DeviceDescriptor Pointer to retrieve REDFISH_INTERFACE_DATA, caller has to free
|
|
this memory using FreePool().
|
|
|
|
@retval EFI_NOT_FOUND No Redfish host interface descriptor provided on this platform.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
RedfishPlatformHostInterfaceDeviceDescriptor (
|
|
IN UINT8 *DeviceType,
|
|
OUT REDFISH_INTERFACE_DATA **DeviceDescriptor
|
|
)
|
|
{
|
|
HOST_INTERFACE_BMC_USB_NIC_INFO *ThisInstance;
|
|
REDFISH_INTERFACE_DATA *InterfaceData;
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry\n", __func__));
|
|
|
|
if (IsListEmpty (&mBmcUsbNic)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
// Check if BMC exposed USB NIC is found and ready for using.
|
|
ThisInstance = (HOST_INTERFACE_BMC_USB_NIC_INFO *)GetFirstNode (&mBmcUsbNic);
|
|
while (TRUE) {
|
|
if (ThisInstance->IsExposedByBmc && ThisInstance->IsSuppportedHostInterface) {
|
|
*DeviceType = REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2;
|
|
|
|
// Fill up REDFISH_INTERFACE_DATA defined in Redfish host interface spec v1.3
|
|
InterfaceData = (REDFISH_INTERFACE_DATA *)AllocateZeroPool (USB_INTERFACE_DEVICE_DESCRIPTOR_V2_SIZE_1_3);
|
|
if (InterfaceData == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Failed to allocate memory for REDFISH_INTERFACE_DATA\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
InterfaceData->DeviceType = REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2;
|
|
InterfaceData->DeviceDescriptor.UsbDeviceV2.Length = USB_INTERFACE_DEVICE_DESCRIPTOR_V2_SIZE_1_3;
|
|
InterfaceData->DeviceDescriptor.UsbDeviceV2.IdVendor = ThisInstance->UsbVendorId;
|
|
InterfaceData->DeviceDescriptor.UsbDeviceV2.IdProduct = ThisInstance->UsbProductId;
|
|
InterfaceData->DeviceDescriptor.UsbDeviceV2.SerialNumberStr = 0;
|
|
CopyMem (
|
|
(VOID *)&InterfaceData->DeviceDescriptor.UsbDeviceV2.MacAddress,
|
|
(VOID *)ThisInstance->MacAddress,
|
|
sizeof (InterfaceData->DeviceDescriptor.UsbDeviceV2.MacAddress)
|
|
);
|
|
InterfaceData->DeviceDescriptor.UsbDeviceV2.Characteristics |= (UINT16)ThisInstance->CredentialBootstrapping;
|
|
InterfaceData->DeviceDescriptor.UsbDeviceV2.CredentialBootstrappingHandle = 0;
|
|
*DeviceDescriptor = InterfaceData;
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " REDFISH_INTERFACE_DATA is returned successfully.\n"));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mBmcUsbNic, &ThisInstance->NextInstance)) {
|
|
break;
|
|
}
|
|
|
|
ThisInstance = (HOST_INTERFACE_BMC_USB_NIC_INFO *)
|
|
GetNextNode (&mBmcUsbNic, &ThisInstance->NextInstance);
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Get platform Redfish host interface protocol data.
|
|
Caller should pass NULL in ProtocolRecord to retrive the first protocol record.
|
|
Then continuously pass previous ProtocolRecord for retrieving the next ProtocolRecord.
|
|
|
|
@param[in, out] ProtocolRecord Pointer to retrieve the first or the next protocol record.
|
|
caller has to free the new protocol record returned from
|
|
this function using FreePool().
|
|
@param[in] IndexOfProtocolData The index of protocol data.
|
|
|
|
@retval EFI_NOT_FOUND No more protocol records.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
RedfishPlatformHostInterfaceProtocolData (
|
|
IN OUT MC_HOST_INTERFACE_PROTOCOL_RECORD **ProtocolRecord,
|
|
IN UINT8 IndexOfProtocolData
|
|
)
|
|
{
|
|
HOST_INTERFACE_BMC_USB_NIC_INFO *ThisInstance;
|
|
MC_HOST_INTERFACE_PROTOCOL_RECORD *ThisProtocolRecord;
|
|
REDFISH_OVER_IP_PROTOCOL_DATA *RedfishOverIpData;
|
|
UINT8 HostNameLength;
|
|
CHAR8 *HostNameString;
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry\n", __func__));
|
|
|
|
if (IsListEmpty (&mBmcUsbNic) || (IndexOfProtocolData > 0)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
ThisInstance = (HOST_INTERFACE_BMC_USB_NIC_INFO *)GetFirstNode (&mBmcUsbNic);
|
|
while (TRUE) {
|
|
if (ThisInstance->IsExposedByBmc && ThisInstance->IsSuppportedHostInterface) {
|
|
// Get the host name before allocating memory.
|
|
HostNameString = (CHAR8 *)PcdGetPtr (PcdRedfishHostName);
|
|
HostNameLength = (UINT8)AsciiStrSize (HostNameString);
|
|
ThisProtocolRecord = (MC_HOST_INTERFACE_PROTOCOL_RECORD *)AllocateZeroPool (
|
|
sizeof (MC_HOST_INTERFACE_PROTOCOL_RECORD) - 1 +
|
|
sizeof (REDFISH_OVER_IP_PROTOCOL_DATA) - 1 +
|
|
HostNameLength
|
|
);
|
|
if (ThisProtocolRecord == NULL) {
|
|
DEBUG ((DEBUG_ERROR, " Allocate memory fail for MC_HOST_INTERFACE_PROTOCOL_RECORD.\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ThisProtocolRecord->ProtocolType = MCHostInterfaceProtocolTypeRedfishOverIP;
|
|
ThisProtocolRecord->ProtocolTypeDataLen = sizeof (REDFISH_OVER_IP_PROTOCOL_DATA) -1 + HostNameLength;
|
|
RedfishOverIpData = (REDFISH_OVER_IP_PROTOCOL_DATA *)&ThisProtocolRecord->ProtocolTypeData[0];
|
|
//
|
|
// Fill up REDFISH_OVER_IP_PROTOCOL_DATA
|
|
//
|
|
|
|
// Service UUID
|
|
ZeroMem ((VOID *)&RedfishOverIpData->ServiceUuid, sizeof (EFI_GUID));
|
|
if (StrLen ((CONST CHAR16 *)PcdGetPtr (PcdRedfishServiceUuid)) != 0) {
|
|
StrToGuid ((CONST CHAR16 *)PcdGetPtr (PcdRedfishServiceUuid), &RedfishOverIpData->ServiceUuid);
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Service UUID: %g", &RedfishOverIpData->ServiceUuid));
|
|
}
|
|
|
|
// HostIpAddressFormat and RedfishServiceIpDiscoveryType
|
|
RedfishOverIpData->HostIpAssignmentType = RedfishHostIpAssignmentUnknown;
|
|
RedfishOverIpData->RedfishServiceIpDiscoveryType = RedfishHostIpAssignmentUnknown;
|
|
if (ThisInstance->IpAssignedType == IpmiStaticAddrsss) {
|
|
RedfishOverIpData->HostIpAssignmentType = RedfishHostIpAssignmentStatic;
|
|
RedfishOverIpData->RedfishServiceIpDiscoveryType = RedfishHostIpAssignmentStatic;
|
|
} else if (ThisInstance->IpAssignedType == IpmiDynamicAddressBmcDhcp) {
|
|
RedfishOverIpData->HostIpAssignmentType = RedfishHostIpAssignmentDhcp;
|
|
RedfishOverIpData->RedfishServiceIpDiscoveryType = RedfishHostIpAssignmentDhcp;
|
|
}
|
|
|
|
// HostIpAddressFormat and RedfishServiceIpAddressFormat, only support IPv4 for now.
|
|
RedfishOverIpData->HostIpAddressFormat = REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP4;
|
|
RedfishOverIpData->RedfishServiceIpAddressFormat = REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP4;
|
|
|
|
// HostIpAddress
|
|
CopyMem (
|
|
(VOID *)RedfishOverIpData->HostIpAddress,
|
|
(VOID *)ThisInstance->HostIpAddressIpv4,
|
|
sizeof (ThisInstance->HostIpAddressIpv4)
|
|
);
|
|
|
|
// HostIpMask and RedfishServiceIpMask
|
|
CopyMem (
|
|
(VOID *)RedfishOverIpData->HostIpMask,
|
|
(VOID *)ThisInstance->SubnetMaskIpv4,
|
|
sizeof (ThisInstance->SubnetMaskIpv4)
|
|
);
|
|
CopyMem (
|
|
(VOID *)RedfishOverIpData->RedfishServiceIpMask,
|
|
(VOID *)ThisInstance->SubnetMaskIpv4,
|
|
sizeof (ThisInstance->SubnetMaskIpv4)
|
|
);
|
|
|
|
// RedfishServiceIpAddress
|
|
CopyMem (
|
|
(VOID *)RedfishOverIpData->RedfishServiceIpAddress,
|
|
(VOID *)ThisInstance->RedfishIpAddressIpv4,
|
|
sizeof (ThisInstance->RedfishIpAddressIpv4)
|
|
);
|
|
|
|
// RedfishServiceIpPort
|
|
RedfishOverIpData->RedfishServiceIpPort = PcdGet16 (PcdRedfishServicePort);
|
|
|
|
// RedfishServiceVlanId
|
|
RedfishOverIpData->RedfishServiceVlanId = ThisInstance->VLanId;
|
|
|
|
// RedfishServiceHostnameLength
|
|
RedfishOverIpData->RedfishServiceHostnameLength = HostNameLength;
|
|
|
|
// Redfish host name.
|
|
CopyMem (
|
|
(VOID *)&RedfishOverIpData->RedfishServiceHostname,
|
|
(VOID *)HostNameString,
|
|
HostNameLength
|
|
);
|
|
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " MC_HOST_INTERFACE_PROTOCOL_RECORD is returned successfully.\n"));
|
|
*ProtocolRecord = ThisProtocolRecord;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mBmcUsbNic, &ThisInstance->NextInstance)) {
|
|
break;
|
|
}
|
|
|
|
ThisInstance = (HOST_INTERFACE_BMC_USB_NIC_INFO *)
|
|
GetNextNode (&mBmcUsbNic, &ThisInstance->NextInstance);
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
This function retrieve the information of BMC USB NIC.
|
|
|
|
@retval EFI_SUCCESS All necessary information is retrieved.
|
|
@retval EFI_NOT_FOUND There is no BMC exposed USB NIC.
|
|
@retval Others Other errors.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
RetrievedBmcUsbNicInfo (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 ResponseDataSize;
|
|
HOST_INTERFACE_BMC_USB_NIC_INFO *ThisInstance;
|
|
IPMI_GET_LAN_CONFIGURATION_PARAMETERS_REQUEST GetLanConfigReq;
|
|
IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *GetLanConfigReps;
|
|
IPMI_LAN_IP_ADDRESS_SRC *IpAddressSrc;
|
|
IPMI_LAN_IP_ADDRESS *DestIpAddress;
|
|
IPMI_LAN_SUBNET_MASK *SubnetMask;
|
|
IPMI_LAN_DEFAULT_GATEWAY *DefaultGateway;
|
|
IPMI_LAN_VLAN_ID *LanVlanId;
|
|
EFI_USB_DEVICE_DESCRIPTOR UsbDeviceDescriptor;
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry\n", __func__));
|
|
|
|
if (IsListEmpty (&mBmcUsbNic)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
ThisInstance = (HOST_INTERFACE_BMC_USB_NIC_INFO *)GetFirstNode (&mBmcUsbNic);
|
|
while (TRUE) {
|
|
if (ThisInstance->IsExposedByBmc) {
|
|
ThisInstance->IsSuppportedHostInterface = FALSE;
|
|
|
|
// Probe if Redfish Host Interface Credential Bootstrapping is supported.
|
|
ThisInstance->CredentialBootstrapping = ProbeRedfishCredentialBootstrap ();
|
|
|
|
// Get IP address source
|
|
GetLanConfigReq.SetSelector = 0;
|
|
GetLanConfigReq.BlockSelector = 0;
|
|
GetLanConfigReq.ChannelNumber.Bits.ChannelNo = ThisInstance->IpmiLanChannelNumber;
|
|
GetLanConfigReq.ChannelNumber.Bits.GetParameter = 0;
|
|
GetLanConfigReq.ChannelNumber.Bits.Reserved = 0;
|
|
GetLanConfigReq.ParameterSelector = IpmiLanIpAddressSource;
|
|
ResponseDataSize = sizeof (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE) + sizeof (IPMI_LAN_IP_ADDRESS_SRC);
|
|
GetLanConfigReps = (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *)AllocateZeroPool (ResponseDataSize);
|
|
GetLanConfigReps->CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
|
|
Status = IpmiGetLanConfigurationParameters (
|
|
&GetLanConfigReq,
|
|
GetLanConfigReps,
|
|
&ResponseDataSize
|
|
);
|
|
if (EFI_ERROR (Status) || (GetLanConfigReps->CompletionCode != IPMI_COMP_CODE_NORMAL)) {
|
|
DEBUG ((DEBUG_ERROR, " Failed to get IP address source at channel %d: %r, 0x%02x.\n", ThisInstance->IpmiLanChannelNumber, Status, GetLanConfigReps->CompletionCode));
|
|
FreePool (GetLanConfigReps);
|
|
return Status;
|
|
}
|
|
|
|
IpAddressSrc = (IPMI_LAN_IP_ADDRESS_SRC *)(GetLanConfigReps + 1);
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " IP address source at channel %d: %x\n", ThisInstance->IpmiLanChannelNumber, IpAddressSrc->Bits.AddressSrc));
|
|
ThisInstance->IpAssignedType = IpAddressSrc->Bits.AddressSrc;
|
|
FreePool (GetLanConfigReps);
|
|
|
|
// Get LAN IPv4 IP address
|
|
GetLanConfigReq.ParameterSelector = IpmiLanIpAddress;
|
|
ResponseDataSize = sizeof (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE) + sizeof (IPMI_LAN_IP_ADDRESS);
|
|
GetLanConfigReps = (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *)AllocateZeroPool (ResponseDataSize);
|
|
GetLanConfigReps->CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
|
|
Status = IpmiGetLanConfigurationParameters (
|
|
&GetLanConfigReq,
|
|
GetLanConfigReps,
|
|
&ResponseDataSize
|
|
);
|
|
if (EFI_ERROR (Status) || (GetLanConfigReps->CompletionCode != IPMI_COMP_CODE_NORMAL)) {
|
|
DEBUG ((DEBUG_ERROR, " Failed to get Dest IP address at channel %d: %r, 0x%02x.\n", ThisInstance->IpmiLanChannelNumber, Status, GetLanConfigReps->CompletionCode));
|
|
FreePool (GetLanConfigReps);
|
|
return Status;
|
|
}
|
|
|
|
DestIpAddress = (IPMI_LAN_IP_ADDRESS *)(GetLanConfigReps + 1);
|
|
DEBUG ((
|
|
DEBUG_REDFISH_HOST_INTERFACE,
|
|
" Dest IP address at channel %d: %d.%d.%d.%d\n",
|
|
ThisInstance->IpmiLanChannelNumber,
|
|
DestIpAddress->IpAddress[0],
|
|
DestIpAddress->IpAddress[1],
|
|
DestIpAddress->IpAddress[2],
|
|
DestIpAddress->IpAddress[3]
|
|
));
|
|
CopyMem ((VOID *)&ThisInstance->RedfishIpAddressIpv4, (VOID *)&DestIpAddress->IpAddress, sizeof (DestIpAddress->IpAddress));
|
|
//
|
|
// According to the design spec:
|
|
// https://github.com/tianocore/edk2/tree/master/RedfishPkg#platform-with-bmc-and-the-bmc-exposed-usb-network-device
|
|
// The IP address at BMC USB NIC host end is the IP address at BMC end minus 1.
|
|
//
|
|
CopyMem ((VOID *)&ThisInstance->HostIpAddressIpv4, (VOID *)&DestIpAddress->IpAddress, sizeof (DestIpAddress->IpAddress));
|
|
ThisInstance->HostIpAddressIpv4[sizeof (ThisInstance->HostIpAddressIpv4) - 1] -= 1;
|
|
FreePool (GetLanConfigReps);
|
|
DEBUG ((
|
|
DEBUG_REDFISH_HOST_INTERFACE,
|
|
" Host IP address at channel %d: %d.%d.%d.%d\n",
|
|
ThisInstance->IpmiLanChannelNumber,
|
|
ThisInstance->HostIpAddressIpv4[0],
|
|
ThisInstance->HostIpAddressIpv4[1],
|
|
ThisInstance->HostIpAddressIpv4[2],
|
|
ThisInstance->HostIpAddressIpv4[3]
|
|
));
|
|
|
|
// Get IPv4 subnet mask
|
|
GetLanConfigReq.ParameterSelector = IpmiLanSubnetMask;
|
|
ResponseDataSize = sizeof (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE) + sizeof (IPMI_LAN_SUBNET_MASK);
|
|
GetLanConfigReps = (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *)AllocateZeroPool (ResponseDataSize);
|
|
GetLanConfigReps->CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
|
|
Status = IpmiGetLanConfigurationParameters (
|
|
&GetLanConfigReq,
|
|
GetLanConfigReps,
|
|
&ResponseDataSize
|
|
);
|
|
if ((EFI_ERROR (Status)) || (GetLanConfigReps->CompletionCode != IPMI_COMP_CODE_NORMAL)) {
|
|
DEBUG ((DEBUG_ERROR, " Failed to get subnet mask at channel %d: %r, 0x%02x.\n", ThisInstance->IpmiLanChannelNumber, Status, GetLanConfigReps->CompletionCode));
|
|
FreePool (GetLanConfigReps);
|
|
return Status;
|
|
}
|
|
|
|
SubnetMask = (IPMI_LAN_SUBNET_MASK *)(GetLanConfigReps + 1);
|
|
DEBUG ((
|
|
DEBUG_REDFISH_HOST_INTERFACE,
|
|
" Subnet mask at channel %d: %d.%d.%d.%d\n",
|
|
ThisInstance->IpmiLanChannelNumber,
|
|
SubnetMask->IpAddress[0],
|
|
SubnetMask->IpAddress[1],
|
|
SubnetMask->IpAddress[2],
|
|
SubnetMask->IpAddress[3]
|
|
));
|
|
CopyMem ((VOID *)&ThisInstance->SubnetMaskIpv4, (VOID *)&SubnetMask->IpAddress, sizeof (SubnetMask->IpAddress));
|
|
FreePool (GetLanConfigReps);
|
|
|
|
// Get Gateway IP address.
|
|
GetLanConfigReq.ParameterSelector = IpmiLanDefaultGateway;
|
|
ResponseDataSize = sizeof (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE) + sizeof (IPMI_LAN_DEFAULT_GATEWAY);
|
|
GetLanConfigReps = (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *)AllocateZeroPool (ResponseDataSize);
|
|
GetLanConfigReps->CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
|
|
Status = IpmiGetLanConfigurationParameters (
|
|
&GetLanConfigReq,
|
|
GetLanConfigReps,
|
|
&ResponseDataSize
|
|
);
|
|
if ((EFI_ERROR (Status)) || (GetLanConfigReps->CompletionCode != IPMI_COMP_CODE_NORMAL)) {
|
|
DEBUG ((DEBUG_ERROR, " Failed to get default gateway at channel %d: %r, 0x%02x.\n", ThisInstance->IpmiLanChannelNumber, Status, GetLanConfigReps->CompletionCode));
|
|
FreePool (GetLanConfigReps);
|
|
return Status;
|
|
}
|
|
|
|
DefaultGateway = (IPMI_LAN_DEFAULT_GATEWAY *)(GetLanConfigReps + 1);
|
|
DEBUG ((
|
|
DEBUG_REDFISH_HOST_INTERFACE,
|
|
" Gateway at channel %d: %d.%d.%d.%d\n",
|
|
ThisInstance->IpmiLanChannelNumber,
|
|
DefaultGateway->IpAddress[0],
|
|
DefaultGateway->IpAddress[1],
|
|
DefaultGateway->IpAddress[2],
|
|
DefaultGateway->IpAddress[3]
|
|
));
|
|
CopyMem ((VOID *)&ThisInstance->GatewayIpv4, (VOID *)&DefaultGateway->IpAddress, sizeof (DefaultGateway->IpAddress));
|
|
FreePool (GetLanConfigReps);
|
|
|
|
// Get VLAN ID
|
|
GetLanConfigReq.ParameterSelector = IpmiLanVlanId;
|
|
ResponseDataSize = sizeof (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE) + sizeof (IPMI_LAN_VLAN_ID);
|
|
GetLanConfigReps = (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *)AllocateZeroPool (ResponseDataSize);
|
|
GetLanConfigReps->CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
|
|
Status = IpmiGetLanConfigurationParameters (
|
|
&GetLanConfigReq,
|
|
GetLanConfigReps,
|
|
&ResponseDataSize
|
|
);
|
|
if ((EFI_ERROR (Status)) || (GetLanConfigReps->CompletionCode != IPMI_COMP_CODE_NORMAL)) {
|
|
DEBUG ((DEBUG_ERROR, " Failed to get VLAN ID at channel %d: %r, 0x%02x.\n", ThisInstance->IpmiLanChannelNumber, Status, GetLanConfigReps->CompletionCode));
|
|
FreePool (GetLanConfigReps);
|
|
return Status;
|
|
}
|
|
|
|
LanVlanId = (IPMI_LAN_VLAN_ID *)(GetLanConfigReps + 1);
|
|
ThisInstance->VLanId = 0;
|
|
if (LanVlanId->Data2.Bits.Enabled == 1) {
|
|
ThisInstance->VLanId = LanVlanId->Data1.VanIdLowByte | (LanVlanId->Data2.Bits.VanIdHighByte << 8);
|
|
}
|
|
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " VLAN ID %x\n", ThisInstance->VLanId));
|
|
|
|
FreePool (GetLanConfigReps);
|
|
|
|
//
|
|
// Read USB device information.
|
|
//
|
|
if (ThisInstance->ThisUsbIo != NULL) {
|
|
Status = ThisInstance->ThisUsbIo->UsbGetDeviceDescriptor (ThisInstance->ThisUsbIo, &UsbDeviceDescriptor);
|
|
if (!EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " USB NIC Vendor ID: 0x%04x, Device ID: 0x%04x\n", UsbDeviceDescriptor.IdVendor, UsbDeviceDescriptor.IdProduct));
|
|
ThisInstance->UsbVendorId = UsbDeviceDescriptor.IdVendor;
|
|
ThisInstance->UsbProductId = UsbDeviceDescriptor.IdProduct;
|
|
} else {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Fail to get USB device descriptor.\n"));
|
|
}
|
|
}
|
|
|
|
// All information is retrieved.
|
|
ThisInstance->IsSuppportedHostInterface = TRUE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mBmcUsbNic, &ThisInstance->NextInstance)) {
|
|
break;
|
|
}
|
|
|
|
ThisInstance = (HOST_INTERFACE_BMC_USB_NIC_INFO *)
|
|
GetNextNode (&mBmcUsbNic, &ThisInstance->NextInstance);
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
This function caches the found IPMI LAN channel. So we
|
|
don't have to sedn IPMI commands again if the USB NIC is
|
|
connected later.
|
|
|
|
@param[in] ChannelNum The IPMI channel number.
|
|
@param[in] IpmiLanChannelMacAddress Pointer to EFI_MAC_ADDRESS.
|
|
@param[in] IpmiLanMacAddressSize The MAC address size.
|
|
|
|
@retval EFI_SUCCESS IPMI LAN channel is cached.
|
|
@retval EFI_OUT_OF_RESOURCE Memory allocated failed.
|
|
@retval Others Other errors.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CacheIpmiLanMac (
|
|
IN UINT8 ChannelNum,
|
|
IN EFI_MAC_ADDRESS *IpmiLanChannelMacAddress,
|
|
IN UINT8 IpmiLanMacAddressSize
|
|
)
|
|
{
|
|
BMC_IPMI_LAN_CHANNEL_INFO *ChannelInfo;
|
|
|
|
ChannelInfo = (BMC_IPMI_LAN_CHANNEL_INFO *)AllocateZeroPool (sizeof (BMC_IPMI_LAN_CHANNEL_INFO));
|
|
if (ChannelInfo == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ChannelInfo->Channel = ChannelNum;
|
|
CopyMem ((VOID *)&ChannelInfo->MacAddress.Addr, (VOID *)IpmiLanChannelMacAddress->Addr, IpmiLanMacAddressSize);
|
|
ChannelInfo->MacAddressSize = IpmiLanMacAddressSize;
|
|
InitializeListHead (&ChannelInfo->NextInstance);
|
|
InsertTailList (&mBmcIpmiLan, &ChannelInfo->NextInstance);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function checks if the IPMI channel already identified
|
|
previously.
|
|
|
|
@param[in] ChannelNum The IPMI channel number.
|
|
@param[out] CachedIpmiLanChannel Pointer to retrieve the cached
|
|
BMC_IPMI_LAN_CHANNEL_INFO.
|
|
|
|
@retval EFI_SUCCESS IPMI LAN channel is found.
|
|
@retval Others Other errors.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CheckCachedIpmiLanMac (
|
|
IN UINT8 ChannelNum,
|
|
OUT BMC_IPMI_LAN_CHANNEL_INFO **CachedIpmiLanChannel
|
|
)
|
|
{
|
|
BMC_IPMI_LAN_CHANNEL_INFO *ThisInstance;
|
|
|
|
if (IsListEmpty (&mBmcIpmiLan)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
ThisInstance = (BMC_IPMI_LAN_CHANNEL_INFO *)GetFirstNode (&mBmcIpmiLan);
|
|
while (TRUE) {
|
|
if (ThisInstance->Channel == ChannelNum) {
|
|
*CachedIpmiLanChannel = ThisInstance;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (IsNodeAtEnd (&mBmcIpmiLan, &ThisInstance->NextInstance)) {
|
|
break;
|
|
}
|
|
|
|
ThisInstance = (BMC_IPMI_LAN_CHANNEL_INFO *)
|
|
GetNextNode (&mBmcIpmiLan, &ThisInstance->NextInstance);
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
This function goes through IPMI channels to find the
|
|
mactched MAC addrss of BMC USB NIC endpoint.
|
|
|
|
@param[in] UsbNicInfo The instance of HOST_INTERFACE_BMC_USB_NIC_INFO.
|
|
|
|
@retval EFI_SUCCESS Yes, USB NIC exposed by BMC is found.
|
|
@retval EFI_NOT_FOUND No, USB NIC exposed by BMC is not found
|
|
on the existing SNP handle.
|
|
@retval Others Other errors.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
HostInterfaceIpmiCheckMacAddress (
|
|
IN HOST_INTERFACE_BMC_USB_NIC_INFO *UsbNicInfo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_STATUS ExitStatus;
|
|
UINTN ChannelNum;
|
|
UINT32 ResponseDataSize;
|
|
IPMI_GET_CHANNEL_INFO_REQUEST GetChanelInfoRequest;
|
|
IPMI_GET_CHANNEL_INFO_RESPONSE GetChanelInfoResponse;
|
|
IPMI_GET_LAN_CONFIGURATION_PARAMETERS_REQUEST GetLanConfigReq;
|
|
IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *GetLanConfigReps;
|
|
BMC_IPMI_LAN_CHANNEL_INFO *CachedIpmiLanChannel;
|
|
UINT8 IpmiLanMacAddressSize;
|
|
EFI_MAC_ADDRESS IpmiLanChannelMacAddress;
|
|
BOOLEAN AlreadyCached;
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry.\n", __func__));
|
|
|
|
GetLanConfigReps = NULL;
|
|
AlreadyCached = FALSE;
|
|
if (!IsListEmpty (&mBmcIpmiLan)) {
|
|
AlreadyCached = TRUE;
|
|
}
|
|
|
|
// Initial the get MAC address request.
|
|
GetLanConfigReq.ChannelNumber.Uint8 = 0;
|
|
GetLanConfigReq.SetSelector = 0;
|
|
GetLanConfigReq.BlockSelector = 0;
|
|
GetLanConfigReq.ParameterSelector = IpmiLanMacAddress;
|
|
|
|
ExitStatus = EFI_NOT_FOUND;
|
|
for (ChannelNum = IPMI_CHANNEL_NUMBER_IMPLEMENTATION_SPECIFIC_1;
|
|
ChannelNum <= IPMI_CHANNEL_NUMBER_IMPLEMENTATION_SPECIFIC_11;
|
|
ChannelNum++)
|
|
{
|
|
IpmiLanMacAddressSize = 0;
|
|
|
|
// Check if the IPMI channel information is already cached.
|
|
Status = EFI_NOT_FOUND;
|
|
if (AlreadyCached) {
|
|
Status = CheckCachedIpmiLanMac ((UINT8)ChannelNum, &CachedIpmiLanChannel);
|
|
}
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Got cached IPMI LAN info.\n"));
|
|
IpmiLanMacAddressSize = sizeof (IPMI_LAN_MAC_ADDRESS);
|
|
CopyMem ((VOID *)&IpmiLanChannelMacAddress.Addr, (VOID *)&CachedIpmiLanChannel->MacAddress.Addr, IpmiLanMacAddressSize);
|
|
} else {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " No cached IPMI LAN info\n"));
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Send NetFn = App, Command = 0x42 to channel %d\n", ChannelNum));
|
|
GetChanelInfoRequest.ChannelNumber.Uint8 = 0;
|
|
GetChanelInfoRequest.ChannelNumber.Bits.ChannelNo = (UINT8)ChannelNum;
|
|
Status = IpmiGetChannelInfo (
|
|
&GetChanelInfoRequest,
|
|
&GetChanelInfoResponse,
|
|
&ResponseDataSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, " - Channel %d fails to send command.\n", ChannelNum));
|
|
continue;
|
|
}
|
|
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " - Response data size = 0x%x\n", ResponseDataSize));
|
|
if ((GetChanelInfoResponse.CompletionCode != IPMI_COMP_CODE_NORMAL) || (ResponseDataSize == 0)) {
|
|
DEBUG ((DEBUG_ERROR, " - Command returned fail: 0x%x.\n", GetChanelInfoResponse.CompletionCode));
|
|
continue;
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_REDFISH_HOST_INTERFACE,
|
|
" - Channel protocol = 0x%x, Media = 0x%x\n",
|
|
GetChanelInfoResponse.ProtocolType.Bits.ChannelProtocolType,
|
|
GetChanelInfoResponse.MediumType.Bits.ChannelMediumType
|
|
));
|
|
|
|
if (GetChanelInfoResponse.ChannelNumber.Bits.ChannelNo != ChannelNum) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
" - ChannelNumber = %d in the response which is not macthed to the request.\n",
|
|
GetChanelInfoResponse.ChannelNumber.Bits.ChannelNo
|
|
));
|
|
continue;
|
|
}
|
|
|
|
if ((GetChanelInfoResponse.MediumType.Bits.ChannelMediumType == IPMI_CHANNEL_MEDIA_TYPE_802_3_LAN) &&
|
|
(GetChanelInfoResponse.ProtocolType.Bits.ChannelProtocolType == IPMI_CHANNEL_PROTOCOL_TYPE_IPMB_1_0))
|
|
{
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " - Channel %d is a LAN device!\n", ChannelNum));
|
|
|
|
ResponseDataSize = sizeof (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE) +
|
|
sizeof (IPMI_LAN_MAC_ADDRESS);
|
|
if (GetLanConfigReps == NULL) {
|
|
GetLanConfigReps =
|
|
(IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *)AllocateZeroPool (ResponseDataSize);
|
|
if (GetLanConfigReps == NULL) {
|
|
DEBUG ((DEBUG_ERROR, " Allocate memory failed for getting MAC address.\n"));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
GetLanConfigReq.ChannelNumber.Bits.ChannelNo = (UINT8)ChannelNum;
|
|
GetLanConfigReps->CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
|
|
Status = IpmiGetLanConfigurationParameters (
|
|
&GetLanConfigReq,
|
|
GetLanConfigReps,
|
|
&ResponseDataSize
|
|
);
|
|
if (EFI_ERROR (Status) || (GetLanConfigReps->CompletionCode != IPMI_COMP_CODE_NORMAL)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
" Fails to get MAC address of channel %d, CompletionCode = %02x.\n",
|
|
ChannelNum,
|
|
GetLanConfigReps->CompletionCode
|
|
));
|
|
continue;
|
|
} else {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " The MAC address of channel %d.\n", ChannelNum));
|
|
DEBUG ((
|
|
DEBUG_REDFISH_HOST_INTERFACE,
|
|
" %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
*((UINT8 *)(GetLanConfigReps + 1) + 0),
|
|
*((UINT8 *)(GetLanConfigReps + 1) + 1),
|
|
*((UINT8 *)(GetLanConfigReps + 1) + 2),
|
|
*((UINT8 *)(GetLanConfigReps + 1) + 3),
|
|
*((UINT8 *)(GetLanConfigReps + 1) + 4),
|
|
*((UINT8 *)(GetLanConfigReps + 1) + 5)
|
|
));
|
|
IpmiLanMacAddressSize = sizeof (IPMI_LAN_MAC_ADDRESS);
|
|
CopyMem ((VOID *)&IpmiLanChannelMacAddress.Addr, (VOID *)(GetLanConfigReps + 1), IpmiLanMacAddressSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IpmiLanMacAddressSize != 0) {
|
|
if (!AlreadyCached) {
|
|
// Cache this IPMI LAN channel.
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Cache this IPMI LAN channel.\n"));
|
|
CacheIpmiLanMac ((UINT8)ChannelNum, &IpmiLanChannelMacAddress, IpmiLanMacAddressSize);
|
|
}
|
|
|
|
//
|
|
// According to design spec in Readme file under RedfishPkg.
|
|
// https://github.com/tianocore/edk2/tree/master/RedfishPkg#platform-with-bmc-and-the-bmc-exposed-usb-network-device
|
|
// Compare the first five elements of MAC address and the 6th element of MAC address.
|
|
// The 6th element of MAC address must be the 6th element of
|
|
// IPMI channel MAC address minus 1.
|
|
//
|
|
if ((IpmiLanMacAddressSize != UsbNicInfo->MacAddressSize) ||
|
|
(CompareMem (
|
|
(VOID *)UsbNicInfo->MacAddress,
|
|
(VOID *)&IpmiLanChannelMacAddress.Addr,
|
|
IpmiLanMacAddressSize - 1
|
|
) != 0) ||
|
|
((IpmiLanChannelMacAddress.Addr[IpmiLanMacAddressSize - 1] - 1) !=
|
|
*(UsbNicInfo->MacAddress + IpmiLanMacAddressSize - 1))
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " MAC address is not matched.\n"));
|
|
continue;
|
|
}
|
|
|
|
// This is the NIC exposed by BMC.
|
|
UsbNicInfo->IpmiLanChannelNumber = (UINT8)ChannelNum;
|
|
UsbNicInfo->IsExposedByBmc = TRUE;
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " MAC address is matched.\n"));
|
|
ExitStatus = EFI_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (GetLanConfigReps != NULL) {
|
|
FreePool (GetLanConfigReps);
|
|
}
|
|
|
|
return ExitStatus;
|
|
}
|
|
|
|
/**
|
|
This function searches the next MSG_USB_DP device path node.
|
|
|
|
@param[in] ThisDevicePath Device path to search.
|
|
|
|
@retval NULL MSG_USB_DP is not found.
|
|
Otherwise MSG_USB_DP is found.
|
|
|
|
**/
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
UsbNicGetNextMsgUsbDp (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *ThisDevicePath
|
|
)
|
|
{
|
|
if (ThisDevicePath == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
while (TRUE) {
|
|
ThisDevicePath = NextDevicePathNode (ThisDevicePath);
|
|
if (IsDevicePathEnd (ThisDevicePath)) {
|
|
return NULL;
|
|
}
|
|
|
|
if ((ThisDevicePath->Type == MESSAGING_DEVICE_PATH) && (ThisDevicePath->SubType == MSG_USB_DP)) {
|
|
return ThisDevicePath;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
This function search the UsbIo handle that matches the UsbDevicePath.
|
|
|
|
@param[in] UsbDevicePath Device path of this SNP handle.
|
|
@param[out] UsbIo Return the UsbIo protocol.
|
|
|
|
@retval EFI_SUCCESS Yes, UsbIo protocl is found.
|
|
@retval EFI_NOT_FOUND No, UsbIo protocl is not found
|
|
@retval Others Other errors.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbNicSearchUsbIo (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *UsbDevicePath,
|
|
OUT EFI_USB_IO_PROTOCOL **UsbIo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BufferSize;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINT16 Length;
|
|
UINTN Index;
|
|
CHAR16 *DevicePathStr;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *ThisDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *ThisDevicePathEnd;
|
|
EFI_DEVICE_PATH_PROTOCOL *ThisUsbDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *ThisUsbDevicePathEnd;
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry.\n", __func__));
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "Device path on the EFI handle which has UsbIo and SNP instaleld on it.\n"));
|
|
DevicePathStr = ConvertDevicePathToText (UsbDevicePath, FALSE, FALSE);
|
|
if (DevicePathStr != NULL) {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "%s\n", DevicePathStr));
|
|
FreePool (DevicePathStr);
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "Failed to convert device path.\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
BufferSize = 0;
|
|
HandleBuffer = NULL;
|
|
*UsbIo = NULL;
|
|
Status = gBS->LocateHandle (
|
|
ByProtocol,
|
|
&gEfiUsbIoProtocolGuid,
|
|
NULL,
|
|
&BufferSize,
|
|
NULL
|
|
);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " %d UsbIo protocol instances.\n", BufferSize/sizeof (EFI_HANDLE)));
|
|
HandleBuffer = AllocateZeroPool (BufferSize);
|
|
if (HandleBuffer == NULL) {
|
|
DEBUG ((DEBUG_ERROR, " Falied to allocate buffer for the handles.\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Status = gBS->LocateHandle (
|
|
ByProtocol,
|
|
&gEfiUsbIoProtocolGuid,
|
|
NULL,
|
|
&BufferSize,
|
|
HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, " Falied to locate UsbIo protocol handles.\n"));
|
|
FreePool (HandleBuffer);
|
|
return Status;
|
|
}
|
|
} else {
|
|
return Status;
|
|
}
|
|
|
|
for (Index = 0; Index < (BufferSize/sizeof (EFI_HANDLE)); Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
*(HandleBuffer + Index),
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **)&ThisDevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "Device path on #%d instance of UsbIo.\n", Index));
|
|
DevicePathStr = ConvertDevicePathToText (ThisDevicePath, FALSE, FALSE);
|
|
if (DevicePathStr != NULL) {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "%s\n", DevicePathStr));
|
|
FreePool (DevicePathStr);
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "Failed to convert device path on #%d instance of UsbIo.\n", Index));
|
|
continue;
|
|
}
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
|
|
// Search for the starting MSG_USB_DP node.
|
|
ThisUsbDevicePath = UsbDevicePath;
|
|
if ((DevicePathType (ThisUsbDevicePath) != MESSAGING_DEVICE_PATH) ||
|
|
(DevicePathSubType (ThisUsbDevicePath) != MSG_USB_DP))
|
|
{
|
|
ThisUsbDevicePath = UsbNicGetNextMsgUsbDp (ThisUsbDevicePath);
|
|
if (ThisUsbDevicePath == NULL) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ((DevicePathType (ThisDevicePath) != MESSAGING_DEVICE_PATH) ||
|
|
(DevicePathSubType (ThisDevicePath) != MSG_USB_DP))
|
|
{
|
|
ThisDevicePath = UsbNicGetNextMsgUsbDp (ThisDevicePath);
|
|
if (ThisDevicePath == NULL) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Search for the ending MSG_USB_DP node.
|
|
ThisDevicePathEnd = ThisDevicePath;
|
|
ThisUsbDevicePathEnd = ThisUsbDevicePath;
|
|
while (TRUE) {
|
|
TempDevicePath = UsbNicGetNextMsgUsbDp (ThisDevicePathEnd);
|
|
if (TempDevicePath == NULL) {
|
|
break;
|
|
}
|
|
|
|
ThisDevicePathEnd = TempDevicePath;
|
|
}
|
|
|
|
while (TRUE) {
|
|
TempDevicePath = UsbNicGetNextMsgUsbDp (ThisUsbDevicePathEnd);
|
|
if (TempDevicePath == NULL) {
|
|
break;
|
|
}
|
|
|
|
ThisUsbDevicePathEnd = TempDevicePath;
|
|
}
|
|
|
|
// Compare these two device paths
|
|
Length = (UINT16)((UINTN)(UINT8 *)ThisDevicePathEnd + DevicePathNodeLength (ThisDevicePathEnd) - (UINTN)(UINT8 *)ThisDevicePath);
|
|
if (Length != ((UINTN)(UINT8 *)ThisUsbDevicePathEnd + DevicePathNodeLength (ThisUsbDevicePathEnd) - (UINTN)(UINT8 *)ThisUsbDevicePath)) {
|
|
continue;
|
|
}
|
|
|
|
if (CompareMem (
|
|
(VOID *)ThisDevicePath,
|
|
(VOID *)ThisUsbDevicePath,
|
|
Length
|
|
) == 0)
|
|
{
|
|
Status = EFI_SUCCESS;
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "EFI handle with the correct UsbIo is found at #%d instance of UsbIo.\n", Index));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
// Locate UsbIo from this handle.
|
|
Status = gBS->HandleProtocol (
|
|
*(HandleBuffer + Index),
|
|
&gEfiUsbIoProtocolGuid,
|
|
(VOID **)UsbIo
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
This function identifies if the USB NIC has MAC address and internet
|
|
protocol device path installed. (Only support IPv4)
|
|
|
|
@param[in] UsbDevicePath USB device path.
|
|
|
|
@retval EFI_SUCCESS Yes, this is IPv4 SNP handle
|
|
@retval EFI_NOT_FOUND No, this is not IPv4 SNP handle
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IdentifyNetworkMessageDevicePath (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *UsbDevicePath
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
|
|
DevicePath = UsbDevicePath;
|
|
while (TRUE) {
|
|
DevicePath = NextDevicePathNode (DevicePath);
|
|
if (IsDevicePathEnd (DevicePath)) {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "MAC address device path is not found on this handle.\n"));
|
|
break;
|
|
}
|
|
|
|
if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_MAC_ADDR_DP)) {
|
|
DevicePath = NextDevicePathNode (DevicePath); // Advance to next device path protocol.
|
|
if (IsDevicePathEnd (DevicePath)) {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "IPv4 device path is not found on this handle.\n"));
|
|
break;
|
|
}
|
|
|
|
if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_IPv4_DP)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
This function identifies if the USB NIC is exposed by BMC as
|
|
the host-BMC channel.
|
|
|
|
@param[in] Handle This is the EFI handle with SNP installed.
|
|
@param[in] UsbDevicePath USB device path.
|
|
|
|
@retval EFI_SUCCESS Yes, USB NIC exposed by BMC is found.
|
|
@retval EFI_NOT_FOUND No, USB NIC exposed by BMC is not found
|
|
on the existing SNP handle.
|
|
@retval Others Other errors.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IdentifyUsbNicBmcChannel (
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *UsbDevicePath
|
|
)
|
|
{
|
|
UINTN Index;
|
|
EFI_STATUS Status;
|
|
EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
|
|
EFI_USB_IO_PROTOCOL *UsbIo;
|
|
HOST_INTERFACE_BMC_USB_NIC_INFO *BmcUsbNic;
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry.\n", __func__));
|
|
Status = gBS->HandleProtocol (
|
|
Handle,
|
|
&gEfiSimpleNetworkProtocolGuid,
|
|
(VOID **)&Snp
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, " Failed to locate SNP.\n"));
|
|
return Status;
|
|
}
|
|
|
|
Status = UsbNicSearchUsbIo (UsbDevicePath, &UsbIo);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, " Failed to find USBIO.\n"));
|
|
return Status;
|
|
}
|
|
|
|
// Get the MAC address of this SNP instance.
|
|
BmcUsbNic = AllocateZeroPool (sizeof (HOST_INTERFACE_BMC_USB_NIC_INFO));
|
|
if (BmcUsbNic == NULL) {
|
|
DEBUG ((DEBUG_ERROR, " Failed to allocate memory for HOST_INTERFACE_BMC_USB_NIC_INFO.\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
InitializeListHead (&BmcUsbNic->NextInstance);
|
|
BmcUsbNic->MacAddressSize = Snp->Mode->HwAddressSize;
|
|
BmcUsbNic->MacAddress = AllocatePool (BmcUsbNic->MacAddressSize);
|
|
if (BmcUsbNic->MacAddress == NULL) {
|
|
DEBUG ((DEBUG_ERROR, " Failed to allocate memory for HW MAC addresss.\n"));
|
|
FreePool (BmcUsbNic);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CopyMem (
|
|
(VOID *)BmcUsbNic->MacAddress,
|
|
(VOID *)&Snp->Mode->CurrentAddress,
|
|
BmcUsbNic->MacAddressSize
|
|
);
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " MAC address (in size %d) for this SNP instance:\n", BmcUsbNic->MacAddressSize));
|
|
for (Index = 0; Index < BmcUsbNic->MacAddressSize; Index++) {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "%02x ", *(BmcUsbNic->MacAddress + Index)));
|
|
}
|
|
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "\n"));
|
|
BmcUsbNic->ThisSnp = Snp;
|
|
BmcUsbNic->ThisUsbIo = UsbIo;
|
|
|
|
Status = HostInterfaceIpmiCheckMacAddress (BmcUsbNic);
|
|
if (Status == EFI_SUCCESS) {
|
|
BmcUsbNic->IsExposedByBmc = TRUE;
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " BMC exposed USB NIC is found.\n"));
|
|
} else {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " BMC exposed USB NIC is not found.\n"));
|
|
}
|
|
|
|
InsertTailList (&mBmcUsbNic, &BmcUsbNic->NextInstance);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function checks if the USB NIC exposed by BMC
|
|
on each handle has SNP protocol installed on it.
|
|
|
|
@param[in] HandleNumer Number of handles to check.
|
|
@param[in] HandleBuffer Handles buffer.
|
|
|
|
@retval EFI_SUCCESS Yes, USB NIC exposed by BMC is found.
|
|
@retval EFI_NOT_FOUND No, USB NIC exposed by BMC is not found
|
|
on the existing SNP handle.
|
|
@retval Others Other errors.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CheckBmcUsbNicOnHandles (
|
|
IN UINTN HandleNumer,
|
|
IN EFI_HANDLE *HandleBuffer
|
|
)
|
|
{
|
|
UINTN Index;
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
BOOLEAN GotBmcUsbNic;
|
|
CHAR16 *DevicePathStr;
|
|
|
|
if ((HandleNumer == 0) || (HandleBuffer == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry, #%d SNP handle\n", __func__, HandleNumer));
|
|
|
|
GotBmcUsbNic = FALSE;
|
|
for (Index = 0; Index < HandleNumer; Index++) {
|
|
DEBUG ((DEBUG_MANAGEABILITY, " Locate device path on handle 0x%08x\n", *(HandleBuffer + Index)));
|
|
Status = gBS->HandleProtocol (
|
|
*(HandleBuffer + Index),
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **)&DevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, " Failed to locate device path on %d handle.\n", Index));
|
|
continue;
|
|
}
|
|
|
|
DevicePathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
|
|
if (DevicePathStr != NULL) {
|
|
DEBUG ((DEBUG_MANAGEABILITY, " Device path: %s\n", DevicePathStr));
|
|
FreePool (DevicePathStr);
|
|
}
|
|
|
|
// Check if this is an BMC exposed USB NIC device.
|
|
while (TRUE) {
|
|
if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_USB_DP)) {
|
|
Status = IdentifyNetworkMessageDevicePath (DevicePath);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = IdentifyUsbNicBmcChannel (*(HandleBuffer + Index), DevicePath);
|
|
if (!EFI_ERROR (Status)) {
|
|
GotBmcUsbNic = TRUE;
|
|
}
|
|
}
|
|
|
|
break; // Advance to next SNP handle.
|
|
}
|
|
|
|
DevicePath = NextDevicePathNode (DevicePath);
|
|
if (IsDevicePathEnd (DevicePath)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GotBmcUsbNic) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "No BMC USB NIC found on SNP handles\n"));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
This function checks if the USB NIC exposed by BMC
|
|
is already connected.
|
|
|
|
@param[in] Registration Locate SNP protocol from the notification
|
|
registeration key.
|
|
NULL means locate SNP protocol from the existing
|
|
handles.
|
|
|
|
@retval EFI_SUCCESS Yes, USB NIC exposed by BMC is found.
|
|
@retval EFI_NOT_FOUND No, USB NIC exposed by BMC is not found
|
|
on the existing SNP handle.
|
|
@retval Others Other errors.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CheckBmcUsbNic (
|
|
VOID *Registration
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE Handle;
|
|
UINTN BufferSize;
|
|
EFI_HANDLE *HandleBuffer;
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry, the registration key - 0x%08x.\n", __func__, Registration));
|
|
|
|
Handle = NULL;
|
|
HandleBuffer = NULL;
|
|
Status = EFI_SUCCESS;
|
|
|
|
do {
|
|
BufferSize = 0;
|
|
Status = gBS->LocateHandle (
|
|
Registration == NULL ? ByProtocol : ByRegisterNotify,
|
|
&gEfiSimpleNetworkProtocolGuid,
|
|
Registration,
|
|
&BufferSize,
|
|
NULL
|
|
);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " %d SNP protocol instance(s).\n", BufferSize/sizeof (EFI_HANDLE)));
|
|
HandleBuffer = AllocateZeroPool (BufferSize);
|
|
if (HandleBuffer == NULL) {
|
|
DEBUG ((DEBUG_ERROR, " Falied to allocate buffer for the handles.\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Status = gBS->LocateHandle (
|
|
Registration == NULL ? ByProtocol : ByRegisterNotify,
|
|
&gEfiSimpleNetworkProtocolGuid,
|
|
Registration,
|
|
&BufferSize,
|
|
HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, " Falied to locate SNP protocol handles.\n"));
|
|
FreePool (HandleBuffer);
|
|
return Status;
|
|
}
|
|
} else if (EFI_ERROR (Status)) {
|
|
if (Registration != NULL) {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " No more newly installed SNP protocol for this registration - %r.\n", Status));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
// Check USB NIC on handles.
|
|
Status = CheckBmcUsbNicOnHandles (BufferSize/sizeof (EFI_HANDLE), HandleBuffer);
|
|
if (!EFI_ERROR (Status)) {
|
|
// Retrieve the rest of BMC USB NIC information for Redfish over IP information
|
|
// and USB Network Interface V2.
|
|
Status = RetrievedBmcUsbNicInfo ();
|
|
if (!EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Install protocol to notify the platform Redfish Host Interface information is ready.\n"));
|
|
Status = gBS->InstallProtocolInterface (
|
|
&Handle,
|
|
&mPlatformHostInterfaceBmcUsbNicReadinessGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, " Install protocol fail %r.\n", Status));
|
|
}
|
|
}
|
|
}
|
|
|
|
FreePool (HandleBuffer);
|
|
} while (Registration != NULL);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Notification event of SNP readiness.
|
|
|
|
@param[in] Event Event whose notification function is being invoked.
|
|
@param[in] Context The pointer to the notification function's context,
|
|
which is implementation-dependent.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
PlatformHostInterfaceSnpCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry.\n", __func__));
|
|
|
|
CheckBmcUsbNic (mPlatformHostInterfaceSnpRegistration);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Get the EFI protocol GUID installed by platform library which
|
|
indicates the necessary information is ready for building
|
|
SMBIOS 42h record.
|
|
|
|
@param[out] InformationReadinessGuid Pointer to retrive the protocol
|
|
GUID.
|
|
|
|
@retval EFI_SUCCESS Notification is required for building up
|
|
SMBIOS type 42h record.
|
|
@retval EFI_UNSUPPORTED Notification is not required for building up
|
|
SMBIOS type 42h record.
|
|
@retval EFI_ALREADY_STARTED Platform host information is already ready.
|
|
@retval Others Other errors.
|
|
**/
|
|
EFI_STATUS
|
|
RedfishPlatformHostInterfaceNotification (
|
|
OUT EFI_GUID **InformationReadinessGuid
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry\n", __func__));
|
|
|
|
*InformationReadinessGuid = NULL;
|
|
InitializeListHead (&mBmcUsbNic);
|
|
InitializeListHead (&mBmcIpmiLan);
|
|
|
|
//
|
|
// Check if USB NIC exposed by BMC is already
|
|
// connected.
|
|
//
|
|
Status = CheckBmcUsbNic (NULL);
|
|
if (!EFI_ERROR (Status)) {
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
if (Status == EFI_NOT_FOUND) {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "%a: BMC USB NIC is not found. Register the notification.\n", __func__));
|
|
|
|
// Register the notification of SNP installation.
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
PlatformHostInterfaceSnpCallback,
|
|
NULL,
|
|
&mPlatformHostInterfaceSnpEvent
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Fail to create event for the installation of SNP protocol.", __func__));
|
|
return Status;
|
|
}
|
|
|
|
Status = gBS->RegisterProtocolNotify (
|
|
&gEfiSimpleNetworkProtocolGuid,
|
|
mPlatformHostInterfaceSnpEvent,
|
|
&mPlatformHostInterfaceSnpRegistration
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Fail to register event for the installation of SNP protocol.", __func__));
|
|
return Status;
|
|
}
|
|
|
|
*InformationReadinessGuid = &mPlatformHostInterfaceBmcUsbNicReadinessGuid;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
DEBUG ((DEBUG_ERROR, "%a: Something wrong when look for BMC USB NIC.\n", __func__));
|
|
return Status;
|
|
}
|