mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-02 13:03:28 +01:00
1292 lines
50 KiB
C
1292 lines
50 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.
|
|
TRUE No, it is not supported.
|
|
|
|
**/
|
|
BOOLEAN
|
|
ProbeRedfishCredentialBootstrap (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
IPMI_BOOTSTRAP_CREDENTIALS_COMMAND_DATA CommandData;
|
|
IPMI_BOOTSTRAP_CREDENTIALS_RESULT_RESPONSE ResponseData;
|
|
UINT32 ResponseSize;
|
|
BOOLEAN ReturnBool;
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry\n", __func__));
|
|
|
|
//
|
|
// IPMI callout to NetFn 2C, command 02
|
|
// Request data:
|
|
// Byte 1: REDFISH_IPMI_GROUP_EXTENSION
|
|
// Byte 2: DisableBootstrapControl
|
|
//
|
|
CommandData.GroupExtensionId = REDFISH_IPMI_GROUP_EXTENSION;
|
|
CommandData.DisableBootstrapControl = REDFISH_IPMI_BOOTSTRAP_CREDENTIAL_ENABLE;
|
|
ResponseData.CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
|
|
ResponseSize = sizeof (ResponseData);
|
|
//
|
|
// Response data: Ignored.
|
|
//
|
|
Status = IpmiSubmitCommand (
|
|
IPMI_NETFN_GROUP_EXT,
|
|
REDFISH_IPMI_GET_BOOTSTRAP_CREDENTIALS_CMD,
|
|
(UINT8 *)&CommandData,
|
|
sizeof (CommandData),
|
|
(UINT8 *)&ResponseData,
|
|
&ResponseSize
|
|
);
|
|
if (!EFI_ERROR (Status) &&
|
|
((ResponseData.CompletionCode == IPMI_COMP_CODE_NORMAL) ||
|
|
(ResponseData.CompletionCode == REDFISH_IPMI_COMP_CODE_BOOTSTRAP_CREDENTIAL_DISABLED)
|
|
))
|
|
{
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Redfish Credential Bootstrapping is supported\n"));
|
|
ReturnBool = TRUE;
|
|
} else {
|
|
DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Redfish Credential Bootstrapping is not supported\n"));
|
|
ReturnBool = FALSE;
|
|
}
|
|
|
|
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) +
|
|
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) + 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 = 0;
|
|
|
|
// 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 UEFI spec, 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.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.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.
|
|
// Compare the first five MAC address and
|
|
// the 6th MAC address.
|
|
//
|
|
if ((IpmiLanMacAddressSize != UsbNicInfo->MacAddressSize) ||
|
|
(CompareMem (
|
|
(VOID *)UsbNicInfo->MacAddress,
|
|
(VOID *)&IpmiLanChannelMacAddress.Addr,
|
|
IpmiLanMacAddressSize - 1
|
|
) != 0) ||
|
|
(IpmiLanChannelMacAddress.Addr[IpmiLanMacAddressSize - 1] !=
|
|
*(UsbNicInfo->MacAddress + IpmiLanMacAddressSize - 1) - 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 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 = AllocateZeroPool (sizeof (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 GotOneUsbNIc;
|
|
|
|
if ((HandleNumer == 0) || (HandleBuffer == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry, #%d SNP handle\n", __func__, HandleNumer));
|
|
|
|
GotOneUsbNIc = FALSE;
|
|
for (Index = 0; Index < HandleNumer; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
*(HandleBuffer + Index),
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **)&DevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, " Failed to locate SNP on %d handle.\n", Index));
|
|
continue;
|
|
}
|
|
|
|
// Check if this is an BMC exposed USB NIC device.
|
|
while (TRUE) {
|
|
if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_USB_DP)) {
|
|
Status = IdentifyUsbNicBmcChannel (*(HandleBuffer + Index), DevicePath);
|
|
if (!EFI_ERROR (Status)) {
|
|
GotOneUsbNIc = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
DevicePath = NextDevicePathNode (DevicePath);
|
|
if (IsDevicePathEnd (DevicePath)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GotOneUsbNIc) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
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;
|
|
Status = EFI_SUCCESS;
|
|
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 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 (
|
|
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)) {
|
|
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);
|
|
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;
|
|
}
|