[edk2-devel] [PATCH 1/3] RedfishPkg/Library: Redfish BMC USBNIC Host Interface

Chang, Abner via groups.io abner.chang=amd.com at groups.io
Mon Mar 20 08:14:34 UTC 2023


[AMD Official Use Only - General]

Hi Nickle,
Thanks for those good comments. V2 patch was just sent!

Abner

> -----Original Message-----
> From: Nickle Wang <nicklew at nvidia.com>
> Sent: Monday, March 20, 2023 11:13 AM
> To: Chang, Abner <Abner.Chang at amd.com>; devel at edk2.groups.io
> Cc: Igor Kulchytskyy <igork at ami.com>
> Subject: RE: [PATCH 1/3] RedfishPkg/Library: Redfish BMC USBNIC Host
> Interface
> 
> Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
> 
> 
> Please find my comment inline below, thanks!
> 
> Regards,
> Nickle
> 
> -----Original Message-----
> From: abner.chang at amd.com <abner.chang at amd.com>
> Sent: Thursday, March 9, 2023 11:41 PM
> To: devel at edk2.groups.io
> Cc: Nickle Wang <nicklew at nvidia.com>; Igor Kulchytskyy <igork at ami.com>
> Subject: [PATCH 1/3] RedfishPkg/Library: Redfish BMC USBNIC Host Interface
> 
> External email: Use caution opening links or attachments
> 
> 
> From: Abner Chang <abner.chang at amd.com>
> 
> BMC exposed USB NIC platform Redfish Host Interface library
> implementation.
> 
> Signed-off-by: Abner Chang <abner.chang at amd.com>
> Cc: Nickle Wang <nicklew at nvidia.com>
> Cc: Igor Kulchytskyy <igork at ami.com>
> ---
>  RedfishPkg/RedfishPkg.dec                     |   10 +
>  .../PlatformHostInterfaceBmcUsbNicLib.inf     |   48 +
>  RedfishPkg/Include/Library/RedfishDebugLib.h  |    3 +-
>  .../PlatformHostInterfaceBmcUsbNicLib.h       |   84 ++
>  .../PlatformHostInterfaceBmcUsbNicLib.c       | 1280 +++++++++++++++++
>  5 files changed, 1424 insertions(+), 1 deletion(-)  create mode 100644
> RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostInterf
> aceBmcUsbNicLib.inf
>  create mode 100644
> RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostInterf
> aceBmcUsbNicLib.h
>  create mode 100644
> RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostInterf
> aceBmcUsbNicLib.c
> 
> diff --git a/RedfishPkg/RedfishPkg.dec b/RedfishPkg/RedfishPkg.dec index
> 53e52c2b008..251aa5e2b76 100644
> --- a/RedfishPkg/RedfishPkg.dec
> +++ b/RedfishPkg/RedfishPkg.dec
> @@ -113,3 +113,13 @@
>    # Default is set to not add.
>    #
> 
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishRestExAddingExpect|FALSE|BOO
> LEAN|0x00001004
> +  #
> +  # Use PCD to declare the Redfish host nmae becasue there is no  #
> + specification for that.
> +  #
> +
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishHostName|""|VOID*|0x0000100
> 5
> +  #
> +  # Use PCD to declare the Redfish service UUID becasue there is no  #
> + specification for that.
> +  #
> +
> +
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceUuid|L""|VOID*|0x00001
> 00
> + 6
> 
> Would it be good to provide dummy string for above PCDs? For example:
> 
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishHostName|"edk2_redfishpkg"|V
> OID*|0x00001005
> gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceUuid|L"0000000000000000
> "|VOID*|0x0000100
> 
> diff --git
> a/RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostInte
> rfaceBmcUsbNicLib.inf
> b/RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostInte
> rfaceBmcUsbNicLib.inf
> new file mode 100644
> index 00000000000..f2c7d7fec89
> --- /dev/null
> +++
> b/RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostI
> +++ nterfaceBmcUsbNicLib.inf
> @@ -0,0 +1,48 @@
> +## @file
> +#  Module 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 # ##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001000b
> +  BASE_NAME                      = PlatformHostInterfaceBmcUsbNicLib
> +  FILE_GUID                      = C4837B58-225E-4352-8FDC-4C52A5D65891
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = PlatformHostInterfaceBmcUsbNicLib
> +
> +[Sources]
> +  PlatformHostInterfaceBmcUsbNicLib.c
> +  PlatformHostInterfaceBmcUsbNicLib.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  NetworkPkg/NetworkPkg.dec
> +  RedfishPkg/RedfishPkg.dec
> +
> +[LibraryClasses]
> +  BaseMemoryLib
> +  DebugLib
> +  IpmiLib
> +  IpmiCommandLib
> +  MemoryAllocationLib
> +  UefiLib
> +  UefiBootServicesTableLib
> +
> +[Protocols]
> +  gEfiSimpleNetworkProtocolGuid                 ## CONSUMED
> +  gEfiUsbIoProtocolGuid                         ## CONSUMED
> +  gEfiDevicePathProtocolGuid                    ## CONSUMED
> +
> +[Pcd]
> +  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishHostName     ## CONSUMED
> +  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishServiceUuid  ## CONSUMED
> +
> +[Depex]
> +  gIpmiProtocolGuid
> diff --git a/RedfishPkg/Include/Library/RedfishDebugLib.h
> b/RedfishPkg/Include/Library/RedfishDebugLib.h
> index 21f01353ede..913f2b2f358 100644
> --- a/RedfishPkg/Include/Library/RedfishDebugLib.h
> +++ b/RedfishPkg/Include/Library/RedfishDebugLib.h
> @@ -14,7 +14,8 @@
>  #include <Library/JsonLib.h>
>  #include <Library/RedfishLib.h>
> 
> -#define DEBUG_REDFISH_NETWORK  DEBUG_INFO   ///< Debug error level
> for Redfish networking function
> +#define DEBUG_REDFISH_NETWORK         DEBUG_INFO   ///< Debug error
> level for Redfish networking function
> +#define DEBUG_REDFISH_HOST_INTERFACE  DEBUG_INFO   ///< Debug
> error level for Redfish networking function
> 
>  /**
> 
> diff --git
> a/RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostInte
> rfaceBmcUsbNicLib.h
> b/RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostInte
> rfaceBmcUsbNicLib.h
> new file mode 100644
> index 00000000000..669c304fc3d
> --- /dev/null
> +++
> b/RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostI
> +++ nterfaceBmcUsbNicLib.h
> @@ -0,0 +1,84 @@
> +/** @file
> +  Header 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
> +
> +**/
> +
> +#ifndef PLATFORM_HOST_INTERFACE_BMC_USB_NIC_LIB_H_
> +#define PLATFORM_HOST_INTERFACE_BMC_USB_NIC_LIB_H_
> +
> +#include <Uefi.h>
> +#include <IndustryStandard/Ipmi.h>
> +#include <IndustryStandard/IpmiNetFnApp.h> #include
> +<IndustryStandard/IpmiNetFnTransport.h>
> +#include <IndustryStandard/RedfishHostInterfaceIpmi.h>
> +#include <IndustryStandard/SmBios.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/IpmiLib.h>
> +#include <Library/IpmiCommandLib.h>
> +#include <Library/RedfishHostInterfaceLib.h>
> +#include <Library/MemoryAllocationLib.h> #include
> +<Library/UefiBootServicesTableLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/RedfishDebugLib.h>
> +
> +#include <Protocol/SimpleNetwork.h>
> +#include <Protocol/UsbIo.h>
> +
> +#define BMC_USB_NIC_HOST_INTERFASCE_READINESS_GUID \
> +    {  \
> +      0xDD96F5D7, 0x4AE1, 0x4E6C, {0xA1, 0x30, 0xA5, 0xAC, 0x77, 0xDD, 0xE4,
> 0xA5} \
> +    }
> +
> +//
> +// This is the structure for BMC exposed // USB NIC information.
> +//
> +typedef struct {
> +  LIST_ENTRY                     NextInstance;              ///< Link to the next instance.
> +  BOOLEAN                        IsExposedByBmc;            ///< Flag indicates this USB
> NIC is
> +                                                            ///< exposed by BMC.
> +  BOOLEAN                        IsSuppportedHostInterface; ///< This BMC USB NIC is
> supported
> +                                                            ///< as Redfish host interface
> +  EFI_SIMPLE_NETWORK_PROTOCOL    *ThisSnp;                  ///< The SNP
> instance associated with
> +                                                            ///< this USB NIC.
> +  EFI_USB_IO_PROTOCOL            *ThisUsbIo;                ///< The USBIO instance
> associated with
> +                                                            ///< this USB NIC.
> +  UINT16                         UsbVendorId;               ///< USB Vendor ID of this BMC
> exposed USB NIC.
> +  UINT16                         UsbProductId;              ///< USB Product ID of this BMC
> exposed USB NIC.
> +  UINTN                          MacAddressSize;            ///< HW address size.
> +  UINT8                          *MacAddress;               ///< HW address.
> +  UINT8                          IpmiLanChannelNumber;      ///< BMC IPMI Lan Channel
> number.
> +
> +  //
> +  // Below is the infortmation for building SMBIOS type 42.
> +  //
> +  UINT8                          IpAssignedType;          ///< Redfish service IP assign type.
> +  UINT8                          IpAddressFormat;         ///< Redfish service IP version.
> +  UINT8                          HostIpAddressIpv4[4];    ///< Host IP address.
> +  UINT8                          RedfishIpAddressIpv4[4]; ///< Redfish service IP
> address.
> +  UINT8                          SubnetMaskIpv4[4];       ///< Subnet mask.
> +  UINT8                          GatewayIpv4[4];          ///< Gateway IP address.
> +  UINT16                         VLanId;                  ///< VLAN ID.
> +  BOOLEAN                        CredentialBootstrapping; ///< If Credential
> bootstrapping is
> +                                                          ///< supported.
> +} HOST_INTERFACE_BMC_USB_NIC_INFO;
> +
> +//
> +// This is the structure for caching
> +// BMC IPMI LAN Channel
> +//
> +typedef struct {
> +  LIST_ENTRY         NextInstance;            ///< Link to the next IPMI LAN
> Channel.
> +  UINT8              Channel;                 ///< IPMI Channel number.
> +  EFI_MAC_ADDRESS    MacAddress;              ///< IPMI LAN Channel MAC
> address.
> +  UINT8              MacAddressSize;          ///< MAC address size;
> +} BMC_IPMI_LAN_CHANNEL_INFO;
> +#endif
> diff --git
> a/RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostInte
> rfaceBmcUsbNicLib.c
> b/RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostInte
> rfaceBmcUsbNicLib.c
> new file mode 100644
> index 00000000000..1c530b692e8
> --- /dev/null
> +++
> b/RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostI
> +++ nterfaceBmcUsbNicLib.c
> @@ -0,0 +1,1280 @@
> +/** @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_INFO, "%a: Entry\n", __FUNCTION__));
> +
> +  //
> +  // 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 Credentail
> Bootstrapping is supported\n", __FUNCTION__));
> +    ReturnBool = TRUE;
> +  } else {
> +    DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "    Redfish Credentail
> Bootstrapping is not supported\n", __FUNCTION__));
> +    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_INFO, "%a: Entry\n", __FUNCTION__));
> +
> +  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_INFO, "%a: Entry\n", __FUNCTION__));
> +
> +  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, "    Aloocate 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);
> +      }
> +
> +      // 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_INFO, "%a: Entry\n", __FUNCTION__));
> +
> +  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_INFO, "%a: Entry.\n", __FUNCTION__));
> +
> +  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, "    - 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_INFO, "%a: Entry.\n", __FUNCTION__));  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);  DEBUG
> + ((DEBUG_REDFISH_HOST_INTERFACE, "%s\n", DevicePathStr));  FreePool
> + (DevicePathStr);
> 
> It would be better to consider the case when ConvertDevicePathToText()
> returns NULL pointer.
> 
> +
> +  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);
> +    DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "%s\n", DevicePathStr));
> +    FreePool (DevicePathStr);
> 
> It would be better to consider the case when ConvertDevicePathToText()
> returns NULL pointer.
> 
> Thanks,
> Nickle
> 
> +
> +    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_INFO, "%a: Entry.\n", __FUNCTION__));  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_INFO, "%a: Entry, #%d SNP handle\n", __FUNCTION__,
> + 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",
> __FUNCTION__, 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_INFO, "%a: Entry, the registration key - 0x%08x.\n",
> + __FUNCTION__, 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_INFO, "%a: Entry.\n", __FUNCTION__));
> +
> +  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_INFO, "%a: Entry\n", __FUNCTION__));
> +
> +  *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", __FUNCTION__));
> +
> +    // 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.", __FUNCTION__));
> +      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.", __FUNCTION__));
> +      return Status;
> +    }
> +
> +    *InformationReadinessGuid =
> &mPlatformHostInterfaceBmcUsbNicReadinessGuid;
> +    return EFI_SUCCESS;
> +  }
> +
> +  DEBUG ((DEBUG_ERROR, "%a: Something wrong when look for BMC USB
> +NIC.\n", __FUNCTION__));
> +  return Status;
> +}
> --
> 2.37.1.windows.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#101409): https://edk2.groups.io/g/devel/message/101409
Mute This Topic: https://groups.io/mt/97498499/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list