[edk2-devel] [PATCH] RedfishPkg/RedfishDiscoverDxe: EFI Redfish Discover Protocol

Abner Chang posted 1 patch 3 years ago
Failed in applying to current master (apply log)
RedfishPkg/RedfishComponents.dsc.inc          |    3 +-
RedfishPkg/Redfish.fdf.inc                    |    3 +-
.../RedfishDiscoverDxe/RedfishDiscoverDxe.inf |   55 +
.../RedfishDiscoverInternal.h                 |  234 ++
RedfishPkg/RedfishDiscoverDxe/ComponentName.c |  218 ++
.../RedfishDiscoverDxe/RedfishDiscoverDxe.c   | 1910 +++++++++++++++++
.../RedfishSmbiosHostInterface.c              |  118 +
7 files changed, 2539 insertions(+), 2 deletions(-)
create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
create mode 100644 RedfishPkg/RedfishDiscoverDxe/ComponentName.c
create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
[edk2-devel] [PATCH] RedfishPkg/RedfishDiscoverDxe: EFI Redfish Discover Protocol
Posted by Abner Chang 3 years ago
EDK2 EFI Redfish Discover Protocol implementation. Refer to UEFI spec 2.9
section 31.1.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Cc: Nickle Wang <nickle.wang@hpe.com>
Cc: Jiaxin Wu <jiaxin.wu@intel.com>
Cc: Siyuan Fu <siyuan.fu@intel.com>
Cc: Fan Wang <fan.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
---
 RedfishPkg/RedfishComponents.dsc.inc          |    3 +-
 RedfishPkg/Redfish.fdf.inc                    |    3 +-
 .../RedfishDiscoverDxe/RedfishDiscoverDxe.inf |   55 +
 .../RedfishDiscoverInternal.h                 |  234 ++
 RedfishPkg/RedfishDiscoverDxe/ComponentName.c |  218 ++
 .../RedfishDiscoverDxe/RedfishDiscoverDxe.c   | 1910 +++++++++++++++++
 .../RedfishSmbiosHostInterface.c              |  118 +
 7 files changed, 2539 insertions(+), 2 deletions(-)
 create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
 create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
 create mode 100644 RedfishPkg/RedfishDiscoverDxe/ComponentName.c
 create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
 create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c

diff --git a/RedfishPkg/RedfishComponents.dsc.inc b/RedfishPkg/RedfishComponents.dsc.inc
index 08f1d3bc32..6f3b055aba 100644
--- a/RedfishPkg/RedfishComponents.dsc.inc
+++ b/RedfishPkg/RedfishComponents.dsc.inc
@@ -6,7 +6,7 @@
 # of EDKII Redfish drivers according to the value of flags described in
 # "RedfishDefines.dsc.inc".
 #
-# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
+# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
 #
 #    SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -17,4 +17,5 @@
   RedfishPkg/RedfishHostInterfaceDxe/RedfishHostInterfaceDxe.inf
   RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf
   RedfishPkg/RedfishCredentialDxe/RedfishCredentialDxe.inf
+  RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
 !endif
diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc
index a64fd119a9..205c3101c0 100644
--- a/RedfishPkg/Redfish.fdf.inc
+++ b/RedfishPkg/Redfish.fdf.inc
@@ -5,7 +5,7 @@
 # by using "!include RedfishPkg/RedfisLibs.fdf.inc" to specify the module instances
 # to be built in the firmware volume.
 #
-# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
+# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
 #
 #    SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -15,4 +15,5 @@
   INF RedfishPkg/RedfishHostInterfaceDxe/RedfishHostInterfaceDxe.inf
   INF RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf
   INF RedfishPkg/RedfishCredentialDxe/RedfishCredentialDxe.inf
+  INF RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
 !endif
diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
new file mode 100644
index 0000000000..345bacf44d
--- /dev/null
+++ b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
@@ -0,0 +1,55 @@
+## @file
+#  Implementation of EFI_REDFISH_DISCOVER_PROTOCOL interfaces.
+#
+#  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION               = 0x0001001b
+  BASE_NAME                 = RedfishDiscoverDxe
+  FILE_GUID                 = 28A76FE5-43D7-48A3-9714-C1B7BDD6DFB6
+  MODULE_TYPE               = UEFI_DRIVER
+  VERSION_STRING            = 1.0
+  ENTRY_POINT               = RedfishDiscoverEntryPoint
+  UNLOAD_IMAGE              = RedfishDiscoverUnload
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  NetworkPkg/NetworkPkg.dec
+  RedfishPkg/RedfishPkg.dec
+
+[Sources]
+  ComponentName.c
+  RedfishDiscoverDxe.c
+  RedfishSmbiosHostInterface.c
+  RedfishDiscoverInternal.h
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  PrintLib
+  RestExLib
+  UefiLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+
+[Protocols]
+  gEfiRestExServiceBindingProtocolGuid            ## Consuming
+  gEfiRestExProtocolGuid                          ## Consuming
+  gEfiTcp4ServiceBindingProtocolGuid              ## Consuming
+  gEfiTcp4ProtocolGuid                            ## Consuming
+  gEfiTcp6ServiceBindingProtocolGuid              ## Consuming
+  gEfiTcp6ProtocolGuid                            ## Consuming
+  gEfiRedfishDiscoverProtocolGuid                 ## Prodcuing
+  gEfiSmbiosProtocolGuid                          ## Consuming
+  gEfiDriverBindingProtocolGuid                   ## Consuming
+
+[Pcd]
+  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishDiscoverAccessModeInBand ## CONSUMES
+
diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
new file mode 100644
index 0000000000..cf69d9231a
--- /dev/null
+++ b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
@@ -0,0 +1,234 @@
+/** @file
+  This file defines the EFI Redfish Discover Protocol interface.
+
+  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EFI_REDFISH_DISCOVER_INTERNAL_H_
+#define EFI_REDFISH_DISCOVER_INTERNAL_H_
+
+#include <Uefi.h>
+
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/RedfishDiscover.h>
+#include <Protocol/Smbios.h>
+#include <Protocol/Tcp4.h>
+#include <Protocol/Tcp6.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NetLib.h>
+#include <Library/PrintLib.h>
+#include <Library/RestExLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+#include <IndustryStandard/RedfishHostInterface.h>
+
+#define REDFISH_DISCOVER_VERSION  0x00010000
+#define EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL TPL_NOTIFY
+
+//
+//GUID definitions
+//
+
+#define EFI_REDFISH_DISCOVER_TCP4_INSTANCE_GUID \
+  { \
+    0xfbab97a4, 0x4c6a, 0xf8e8, { 0xf2, 0x25, 0x42, 0x8a, 0x80, 0x3f, 0xb6, 0xaa } \
+  }
+
+#define EFI_REDFISH_DISCOVER_TCP6_INSTANCE_GUID \
+  { \
+    0xbe513b6d, 0x41c1, 0x96Ed, { 0x8d, 0xaf, 0x3e, 0x89, 0xc5, 0xf5, 0x02, 0x25 } \
+  }
+
+#define EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_GUID \
+  { \
+    0xc44a6076, 0xd42a, 0x4d54, { 0x85, 0x6d, 0x98, 0x8a, 0x85, 0x8f, 0xa1, 0x11 } \
+  }
+
+extern EFI_COMPONENT_NAME_PROTOCOL   gRedfishDiscoverComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gRedfishDiscoverComponentName2;
+extern EFI_UNICODE_STRING_TABLE      *gRedfishDiscoverControllerNameTable;
+
+//
+// Enumeration of network protocols
+// required for the Redfish service discovery.
+//
+typedef enum {
+  ProtocolTypeTcp4 = 0, ///< Network protocol TCPv4.
+  ProtocolTypeTcp6,     ///< Network protocol TCCv6.
+  ProtocolTypeRestEx,   ///< REST EX over network protocol.
+  MaxProtocolType
+} NETWORK_INTERFACE_PROTOCOL_TYPE;
+
+//
+// Network protocol information installed on
+// the network interface.
+//
+typedef struct {
+  EFI_GUID ProtocolGuid;                ///< Network protocol GUID.
+  EFI_GUID ProtocolServiceGuid;         ///< Network protocol service GUID.
+  UINT32   ProtocolDiscoverId;          ///< The identifier installed on network protocol handle.
+  EFI_HANDLE ProtocolControllerHandle;  ///< The controller handle on network protocol.
+  VOID *NetworkProtocolInterface;       ///< The protocol interface of network protocol.
+} REDFISH_DISCOVER_NETWORK_INTERFACE_PROTOCOL;
+
+//
+// Internal structure used to maintain network
+// interface properties.
+//
+typedef struct {
+  LIST_ENTRY      Entry;                        ///< Link list entry.
+  EFI_HANDLE      OpenDriverAgentHandle;        ///< The agent to open network protocol.
+  EFI_HANDLE      OpenDriverControllerHandle;   ///< The controller handle to open network protocol.
+  UINTN           HwAddressSize;                ///< The size of network interface hardware address.
+  EFI_MAC_ADDRESS MacAddress;                   ///< MAC address of network interface.
+  CHAR16          *StrMacAddr;                  ///< String to MAC address of network interface.
+  BOOLEAN         GotSubnetInfo;                ///< Indicates sub net information is retrieved.
+  EFI_IP_ADDRESS  SubnetAddr;                   ///< Subnet ID.
+  EFI_IP_ADDRESS  SubnetMask;                   ///< Subnet mask (IPv4 only)
+  UINT8           SubnetPrefixLength;           ///< Subnet prefix.
+  UINT16          VlanId;                       ///< VLAN ID
+  UINT32          SubnetAddrInfoIPv6Number;     ///< IPv6 address info number.
+  EFI_IP6_ADDRESS_INFO *SubnetAddrInfoIPv6;     ///< IPv6 address info.
+  //
+  // Network interface protocol and REST EX infor.
+  //
+  UINT32          NetworkProtocolType;          ///< Network protocol type. Refer to
+                                                ///< NETWORK_INTERFACE_PROTOCOL_TYPE.
+  REDFISH_DISCOVER_NETWORK_INTERFACE_PROTOCOL NetworkInterfaceProtocolInfo; ///< Network interface protocol information.
+  EFI_HANDLE      RestExHandle;                 ///< REST EX handle associated with this network interface.
+} EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL;
+
+//
+// Internal structure used to maintain REST EX properties.
+//
+typedef struct {
+    LIST_ENTRY      Entry;                          ///< Link list entry.
+    EFI_HANDLE      OpenDriverAgentHandle;          ///< The agent to open network protocol.
+    EFI_HANDLE      OpenDriverControllerHandle;     ///< The controller handle to open network protocol.
+    EFI_HANDLE      RestExChildHandle;              ///< The child handle created throught REST EX Service Protocol.
+    EFI_HANDLE      RestExControllerHandle;         ///< The controller handle which provide REST EX protocol.
+    EFI_REST_EX_PROTOCOL *RestExProtocolInterface;  ///< Pointer to EFI_REST_EX_PROTOCOL.
+    UINT32          RestExId;                       ///< The identifier installed on REST EX controller handle.
+} EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL;
+
+/**
+  This function to get subnet information.
+
+  @param[in]            ImageHandle  EFI handle with this image.
+  @param[in]            Instance  Instance of Network interface.
+  @retval EFI_STATUS    Get subnet information successfully.
+  @retval Otherwise     Fail to get subnet information.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REDFISH_DISCOVER_GET_SUBNET_INFO)(
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
+);
+
+//
+// The require network protocol matrix.
+//
+typedef struct {
+  UINT32   ProtocolType;                                ///< Network protocol type,
+                                                        ///< Refer to NETWORK_INTERFACE_PROTOCOL_TYPE.
+  CHAR16   *ProtocolName;                               ///< Protocol name.
+  EFI_GUID *RequiredProtocolGuid;                       ///< Network protocol interface GUID.
+  EFI_GUID *RequiredServiceBindingProtocolGuid;         ///< Network protocol service GUID.
+  EFI_GUID *DiscoveredProtocolGuid;                     ///< Protocol interface GUID use to install identifier.
+  EFI_REDFISH_DISCOVER_GET_SUBNET_INFO GetSubnetInfo;   ///< Function of getting subnet information.
+} REDFISH_DISCOVER_REQUIRED_PROTOCOL;
+
+//
+// Link list of Redfish discover instance.
+//
+typedef struct {
+  LIST_ENTRY  NextInstance;                             ///< Next list.
+  EFI_REDFISH_DISCOVERED_INSTANCE *Instance;            ///< Pointer to EFI_REDFISH_DISCOVERED_INSTANCE.
+} EFI_REDFISH_DISCOVERED_INTERNAL_LIST;
+
+//
+// Internal structure of Redfish discover instance.
+//
+typedef struct {
+  LIST_ENTRY  Entry;                                    ///< Link list entry.
+  EFI_HANDLE  Owner;                                    ///< The owner owns this Redfish service discovery.
+                                                        ///< It's the EFI image handle of driver uses
+                                                        ///< EFI Redfish Discover Protocol.
+  EFI_REDFISH_DISCOVER_FLAG DiscoverFlags;              ///< EFI_REDFISH_DISCOVER_FLAG
+  EFI_REDFISH_DISCOVERED_TOKEN *DiscoverToken;          ///< Token used to signal when Redfish service is discovered.
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NetworkInterface; ///< EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
+                                                                     ///< instance used to discover Redfish service.
+  //
+  // Below for Host insterface discovery.
+  //
+  BOOLEAN         HostIntfValidation;                   ///< Indicates whether to validate Redfish Host interface.
+  EFI_IP_ADDRESS  TargetIpAddress;                      ///< Target IP address reported in Redfish Host interface.
+} EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE;
+
+/**
+  The function adds a new foudn Redfish service to internal list and
+  notify clinet.
+
+  It simply frees the packet.
+
+  @param[in]  Instance              EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
+  @param[in]  RedfishVersion        Redfish version.
+  @param[in]  RedfishLocation       Redfish location.
+  @param[in]  Uuid                  Service UUID string.
+  @param[in]  Os                    OS string.
+  @param[in]  OsVer                 OS version string.
+  @param[in]  Product               Product string.
+  @param[in]  ProductVer            Product verison string.
+  @param[in]  UseHttps              Redfish service requires secured connection.
+  @retval EFI_SUCCESS               Redfish service is added to list successfully.
+
+**/
+EFI_STATUS
+AddAndSignalNewRedfishService (
+  IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
+  IN UINTN *RedfishVersion OPTIONAL,
+  IN CHAR8 *RedfishLocation OPTIONAL,
+  IN CHAR8 *Uuid  OPTIONAL,
+  IN CHAR8 *Os  OPTIONAL,
+  IN CHAR8 *OsVer  OPTIONAL,
+  IN CHAR8 *Product  OPTIONAL,
+  IN CHAR8 *ProductVer  OPTIONAL,
+  IN BOOLEAN UseHttps
+  );
+
+/**
+  The function gets information reported in Redfish Host Interface.
+
+  It simply frees the packet.
+
+  @param[in]  Smbios           SMBIOS protocol.
+  @param[out] DeviceDescriptor Pointer to REDFISH_INTERFACE_DATA.
+  @param[out] ProtocolData     Pointer to REDFISH_OVER_IP_PROTOCOL_DATA.
+
+  @retval EFI_SUCCESS    Get host interface succesfully.
+  @retval Otherwise      Fail to tet host interface.
+
+**/
+EFI_STATUS
+RedfishGetHostInterfaceProtocolData (
+  IN EFI_SMBIOS_PROTOCOL              *Smbios,
+  OUT REDFISH_INTERFACE_DATA          **DeviceDescriptor,
+  OUT REDFISH_OVER_IP_PROTOCOL_DATA   **ProtocolData
+  );
+
+extern EFI_GUID gRedfishDiscoverTcp4Instance;
+extern EFI_GUID gRedfishDiscoverTcp6Instance;
+extern EFI_GUID gRedfishDiscoverRestEXInstance;
+#endif
diff --git a/RedfishPkg/RedfishDiscoverDxe/ComponentName.c b/RedfishPkg/RedfishDiscoverDxe/ComponentName.c
new file mode 100644
index 0000000000..adad2504bc
--- /dev/null
+++ b/RedfishPkg/RedfishDiscoverDxe/ComponentName.c
@@ -0,0 +1,218 @@
+/** @file
+  Implementation of EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL protocol.
+  for EFI Refish Discover Protocol
+
+  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishDiscoverInternal.h"
+
+//
+// EFI Component Name Functions
+//
+/**
+  Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+  @param[in]  This       A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  Language   A pointer to a three-character ISO 639-2 language identifier.
+                         This is the language of the driver name that that the caller
+                         is requesting, and it must match one of the languages specified
+                         in SupportedLanguages.  The number of languages supported by a
+                         driver is up to the driver writer.
+  @param[out] DriverName A pointer to the Unicode string to return.  This Unicode string
+                         is the name of the driver specified by This in the language
+                         specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by This
+                                and the language specified by Language was returned
+                                in DriverName.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  );
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by an EFI Driver.
+
+  @param[in]  This             A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  ControllerHandle The handle of a controller that the driver specified by
+                               This is managing.  This handle specifies the controller
+                               whose name is to be returned.
+  @param[in]  ChildHandle      The handle of the child controller to retrieve the name
+                               of.  This is an optional parameter that may be NULL.  It
+                               will be NULL for device drivers.  It will also be NULL
+                               for a bus drivers that wish to retrieve the name of the
+                               bus controller.  It will not be NULL for a bus driver
+                               that wishes to retrieve the name of a child controller.
+  @param[in]  Language         A pointer to a three character ISO 639-2 language
+                               identifier.  This is the language of the controller name
+                               that the caller is requesting, and it must match one
+                               of the languages specified in SupportedLanguages.  The
+                               number of languages supported by a driver is up to the
+                               driver writer.
+  @param[out]  ControllerName  A pointer to the Unicode string to return.  This Unicode
+                               string is the name of the controller specified by
+                               ControllerHandle and ChildHandle in the language specified
+                               by Language, from the point of view of the driver specified
+                               by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user-readable name in the
+                                language specified by Language for the driver
+                                specified by This was returned in DriverName.
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently managing
+                                the controller specified by ControllerHandle and
+                                ChildHandle.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  EFI_HANDLE                    ControllerHandle,
+  IN  EFI_HANDLE                    ChildHandle        OPTIONAL,
+  IN  CHAR8                         *Language,
+  OUT CHAR16                        **ControllerName
+  );
+
+
+///
+/// Component Name Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME_PROTOCOL  gRedfishDiscoverComponentName = {
+  RedfishDiscoverComponentNameGetDriverName,
+  RedfishDiscoverComponentNameGetControllerName,
+  "eng"
+};
+
+///
+/// Component Name 2 Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME2_PROTOCOL  gRedfishDiscoverComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     RedfishDiscoverComponentNameGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) RedfishDiscoverComponentNameGetControllerName,
+  "en"
+};
+
+///
+/// Table of driver names
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_UNICODE_STRING_TABLE mRedfishDiscoverDriverNameTable[] = {
+  { "eng;en", (CHAR16 *)L"Redfish Discover UEFI Driver" },
+  { NULL, NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gRedfishDiscoverControllerNameTable = NULL;
+
+/**
+  Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+  @param[in]  This        A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  Language    A pointer to a three-character ISO 639-2 language identifier.
+                          This is the language of the driver name that that the caller
+                          is requesting, and it must match one of the languages specified
+                          in SupportedLanguages.  The number of languages supported by a
+                          driver is up to the driver writer.
+  @param[out]  DriverName A pointer to the Unicode string to return.  This Unicode string
+                          is the name of the driver specified by This in the language
+                          specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by This
+                                and the language specified by Language was returned
+                                in DriverName.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mRedfishDiscoverDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gRedfishDiscoverComponentName)
+           );
+}
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by an EFI Driver.
+
+  @param[in]  This             A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  ControllerHandle The handle of a controller that the driver specified by
+                               This is managing.  This handle specifies the controller
+                               whose name is to be returned.
+  @param[in]  ChildHandle      The handle of the child controller to retrieve the name
+                               of.  This is an optional parameter that may be NULL.  It
+                               will be NULL for device drivers.  It will also be NULL
+                               for a bus drivers that wish to retrieve the name of the
+                               bus controller.  It will not be NULL for a bus driver
+                               that wishes to retrieve the name of a child controller.
+  @param[in]  Language         A pointer to a three character ISO 639-2 language
+                               identifier.  This is the language of the controller name
+                               that the caller is requesting, and it must match one
+                               of the languages specified in SupportedLanguages.  The
+                               number of languages supported by a driver is up to the
+                              driver writer.
+  @param[out]  ControllerName  A pointer to the Unicode string to return.  This Unicode
+                               string is the name of the controller specified by
+                               ControllerHandle and ChildHandle in the language specified
+                               by Language, from the point of view of the driver specified
+                               by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user-readable name in the
+                                language specified by Language for the driver
+                                specified by This was returned in DriverName.
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently managing
+                                the controller specified by ControllerHandle and
+                                ChildHandle.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  EFI_HANDLE                    ControllerHandle,
+  IN  EFI_HANDLE                    ChildHandle        OPTIONAL,
+  IN  CHAR8                         *Language,
+  OUT CHAR16                        **ControllerName
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
new file mode 100644
index 0000000000..80d70a4679
--- /dev/null
+++ b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
@@ -0,0 +1,1910 @@
+/** @file
+
+  The implementation of EFI Redfidh Discover Protocol.
+
+  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishDiscoverInternal.h"
+
+LIST_ENTRY mRedfishDiscoverList;
+LIST_ENTRY mRedfishInstanceList;
+EFI_SMBIOS_PROTOCOL *mSmbios = NULL;
+
+UINTN mNumNetworkInterface = 0;
+UINTN mNumRestExInstance = 0;
+LIST_ENTRY mEfiRedfishDiscoverNetworkInterface;
+LIST_ENTRY mEfiRedfishDiscoverRestExInstance;
+
+EFI_GUID mRedfishDiscoverTcp4InstanceGuid = EFI_REDFISH_DISCOVER_TCP4_INSTANCE_GUID;
+EFI_GUID mRedfishDiscoverTcp6InstanceGuid = EFI_REDFISH_DISCOVER_TCP6_INSTANCE_GUID;
+EFI_GUID mRedfishDiscoverRestExInstanceGuid = EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_GUID;
+
+EFI_HANDLE EfiRedfishDiscoverProtocolHandle = NULL;
+
+EFI_STATUS
+EFIAPI
+Tcp4GetSubnetInfo (
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
+);
+
+EFI_STATUS
+EFIAPI
+Tcp6GetSubnetInfo (
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
+);
+
+static REDFISH_DISCOVER_REQUIRED_PROTOCOL gRequiredProtocol[] = {
+  {
+    ProtocolTypeTcp4,
+    L"TCP4 Service Binding Protocol",
+    &gEfiTcp4ProtocolGuid,
+    &gEfiTcp4ServiceBindingProtocolGuid,
+    &mRedfishDiscoverTcp4InstanceGuid,
+    Tcp4GetSubnetInfo
+  },
+  {
+    ProtocolTypeTcp6,
+    L"TCP6 Service Binding Protocol",
+    &gEfiTcp6ProtocolGuid,
+    &gEfiTcp6ServiceBindingProtocolGuid,
+    &mRedfishDiscoverTcp6InstanceGuid,
+    Tcp6GetSubnetInfo
+  },
+  {
+    ProtocolTypeRestEx,
+    L"REST EX Service Binding Protocol",
+    &gEfiRestExProtocolGuid,
+    &gEfiRestExServiceBindingProtocolGuid,
+    &mRedfishDiscoverRestExInstanceGuid,
+    NULL
+  }
+};
+
+/**
+  This function creates REST EX instance for the found Resfish service.
+  by known owner handle.
+
+  @param[in]    Instance        EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
+  @param[in]    Token           Client token.
+
+  @retval NULL  Instance not found.
+  @retval EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE The instance owned by this owner.
+
+**/
+EFI_STATUS
+CreateRestExInstance (
+  IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
+  IN EFI_REDFISH_DISCOVERED_TOKEN *Token
+  )
+{
+  EFI_STATUS Status;
+
+  Status = RestExLibCreateChild (
+            Instance->Owner,
+            FixedPcdGetBool (PcdRedfishDiscoverAccessModeInBand)? EfiRestExServiceInBandAccess: EfiRestExServiceOutOfBandAccess,
+            EfiRestExConfigHttp,
+            EfiRestExServiceRedfish,
+            &Token->DiscoverList.RedfishInstances->Information.RedfishRestExHandle
+            );
+  return Status;
+}
+
+/**
+  This function gets EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
+  by known owner handle.
+
+  @param[in]    ImageHandle             Image handle owns EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
+  @param[in]    TargetNetworkInterface  Target network interface used by this EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
+  @param[in]    DiscoverFlags           EFI_REDFISH_DISCOVER_FLAG
+
+  @retval NULL  Instance not found.
+  @retval EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE The instance owned by this owner.
+
+**/
+EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *
+GetInstanceByOwner (
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *TargetNetworkInterface,
+  IN EFI_REDFISH_DISCOVER_FLAG DiscoverFlags
+  )
+{
+  EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *ThisInstance;
+
+  if (IsListEmpty (&mRedfishDiscoverList)) {
+    return NULL;
+  }
+  ThisInstance =
+    (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)GetFirstNode (&mRedfishDiscoverList);
+  while (TRUE) {
+    if ((ThisInstance->Owner == ImageHandle) &&
+         (ThisInstance->DiscoverFlags == DiscoverFlags) &&
+         (ThisInstance->NetworkInterface == TargetNetworkInterface)) {
+      return ThisInstance;
+    }
+    if (IsNodeAtEnd (&mRedfishDiscoverList, &ThisInstance->Entry)) {
+      break;
+    }
+    ThisInstance =
+      (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)GetNextNode (&mRedfishDiscoverList, &ThisInstance->Entry);
+  };
+  return NULL;
+}
+
+/**
+  This function gets the subnet information of this TCP4 instance.
+
+  @param[in]            ImageHandle  EFI handle with this image.
+  @param[in]            Instance  Instance of Network interface.
+  @retval EFI_STATUS    Get subnet information successfully.
+  @retval Otherwise     Fail to get subnet information.
+**/
+EFI_STATUS
+EFIAPI
+Tcp4GetSubnetInfo (
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
+)
+{
+  EFI_STATUS Status;
+  EFI_TCP4_PROTOCOL *Tcp4;
+  EFI_TCP4_CONFIG_DATA Tcp4CfgData;
+  EFI_TCP4_OPTION Tcp4Option;
+  EFI_IP4_MODE_DATA IpModedata;
+  UINT8 SubnetMaskIndex;
+  UINT8 BitMask;
+  UINT8 PrefixLength;
+  BOOLEAN GotPrefixLength;
+
+  if (Instance == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  Tcp4 = (EFI_TCP4_PROTOCOL *)Instance->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
+
+  ZeroMem ((VOID *)&Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
+  ZeroMem ((VOID *)&Tcp4Option, sizeof (EFI_TCP4_OPTION));
+  // Give a local host IP address just for getting subnet information.
+  Tcp4CfgData.AccessPoint.UseDefaultAddress = TRUE;
+  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [0] = 127;
+  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [1] = 0;
+  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [2] = 0;
+  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [3] = 1;
+  Tcp4CfgData.AccessPoint.RemotePort  = 80;
+  Tcp4CfgData.AccessPoint.ActiveFlag  = TRUE;
+
+  Tcp4CfgData.ControlOption = &Tcp4Option;
+  Tcp4Option.ReceiveBufferSize      = 65535;
+  Tcp4Option.SendBufferSize         = 65535;
+  Tcp4Option.MaxSynBackLog          = 5;
+  Tcp4Option.ConnectionTimeout      = 60;
+  Tcp4Option.DataRetries            = 12;
+  Tcp4Option.FinTimeout             = 2;
+  Tcp4Option.KeepAliveProbes        = 6;
+  Tcp4Option.KeepAliveTime          = 7200;
+  Tcp4Option.KeepAliveInterval      = 30;
+  Tcp4Option.EnableNagle            = TRUE;
+  Status = Tcp4->Configure (Tcp4, &Tcp4CfgData);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Can't get subnet information\n", __FUNCTION__));
+    return Status;
+  }
+  Status = Tcp4->GetModeData (Tcp4, NULL, NULL, &IpModedata, NULL, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Can't get IP mode data information\n", __FUNCTION__));
+    return Status;
+  }
+  IP4_COPY_ADDRESS (&Instance->SubnetMask, &IpModedata.ConfigData.SubnetMask);
+  Instance->SubnetAddr.v4.Addr [0] = IpModedata.ConfigData.StationAddress.Addr [0] & Instance->SubnetMask.v4.Addr [0];
+  Instance->SubnetAddr.v4.Addr [1] = IpModedata.ConfigData.StationAddress.Addr [1] & Instance->SubnetMask.v4.Addr [1];
+  Instance->SubnetAddr.v4.Addr [2] = IpModedata.ConfigData.StationAddress.Addr [2] & Instance->SubnetMask.v4.Addr [2];
+  Instance->SubnetAddr.v4.Addr [3] = IpModedata.ConfigData.StationAddress.Addr [3] & Instance->SubnetMask.v4.Addr [3];
+  //
+  // Calculate the subnet mask prefix.
+  //
+  GotPrefixLength = FALSE;
+  PrefixLength = 0;
+  SubnetMaskIndex = 0;
+  while (GotPrefixLength == FALSE && SubnetMaskIndex < 4) {
+    BitMask = 0x80;
+    while (BitMask != 0) {
+      if ((Instance->SubnetMask.v4.Addr [SubnetMaskIndex] & BitMask) != 0) {
+        PrefixLength ++;
+      } else {
+        GotPrefixLength = TRUE;
+        break;
+      }
+      BitMask = BitMask >> 1;
+    };
+    SubnetMaskIndex ++;
+  };
+  Instance->SubnetPrefixLength = PrefixLength;
+  return EFI_SUCCESS;
+}
+
+/**
+  This function gets the subnet information of this TCP6 instance.
+
+  @param[in]            ImageHandle  EFI handle with this image.
+  @param[in]            Instance  Instance of Network interface.
+  @retval EFI_STATUS    Get subnet information successfully.
+  @retval Otherwise     Fail to get subnet information.
+**/
+EFI_STATUS
+EFIAPI
+Tcp6GetSubnetInfo (
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
+)
+{
+  EFI_STATUS Status;
+  EFI_TCP6_PROTOCOL *Tcp6;
+  EFI_IP6_MODE_DATA IpModedata;
+
+  if (Instance == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  Tcp6 = (EFI_TCP6_PROTOCOL *)Instance->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
+
+  Status = Tcp6->GetModeData (Tcp6, NULL, NULL, &IpModedata, NULL, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Can't get IP mode data information\n"));
+    return Status;
+  }
+  if (IpModedata.AddressCount == 0) {
+    DEBUG ((DEBUG_INFO, "%a: No IPv6 address configured.\n"));
+  }
+  if (Instance->SubnetAddrInfoIPv6 != NULL) {
+    FreePool (Instance->SubnetAddrInfoIPv6);
+  }
+  Instance->SubnetAddrInfoIPv6 = AllocateZeroPool (IpModedata.AddressCount * sizeof (EFI_IP6_ADDRESS_INFO));
+  if (Instance->SubnetAddrInfoIPv6 == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to allocate memory fir IPv6 subnet address information\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  Instance->SubnetAddrInfoIPv6Number = IpModedata.AddressCount;
+  CopyMem (
+    (VOID *)Instance->SubnetAddrInfoIPv6,
+    (VOID *)&IpModedata.AddressList,
+    IpModedata.AddressCount * sizeof (EFI_IP6_ADDRESS_INFO)
+    );
+  FreePool (IpModedata.AddressList);
+  return EFI_SUCCESS;
+}
+
+/**
+  This function searches EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
+  instance with the given  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
+
+  @param[in] TargetNetworkInterface  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
+                                     NULL for all EFI_REDFISH_DISCOVER_NETWORK_INTERFACEs.
+
+  @retval Non-NULL  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL is returned.
+  @retval NULL      Non of EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance is returned.
+**/
+EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *
+GetTargetNetworkInterfaceInternal (
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE  *TargetNetworkInterface
+  )
+{
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
+
+  ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+  while (TRUE) {
+    if (CompareMem((VOID *)&ThisNetworkInterface->MacAddress, &TargetNetworkInterface->MacAddress, ThisNetworkInterface->HwAddressSize) == 0) {
+      return ThisNetworkInterface;
+    }
+    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
+      return NULL;
+    }
+    ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
+  };
+  return NULL;
+}
+
+/**
+  This function validate if target network interface is ready for discovering
+  Redfish service.
+
+  @param[in] TargetNetworkInterface  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
+                                     NULL for all EFI_REDFISH_DISCOVER_NETWORK_INTERFACEs.
+  @param[in] Flags                   EFI_REDFISH_DISCOVER_FLAG
+
+  @retval EFI_SUCCESS     Target network interface is ready to use.
+  @retval EFI_UNSUPPORTED Target network interface is not ready to use.
+**/
+EFI_STATUS
+ValidateTargetNetworkInterface (
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE  *TargetNetworkInterface,
+  IN EFI_REDFISH_DISCOVER_FLAG Flags
+  )
+{
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
+
+  if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface) && TargetNetworkInterface == NULL) {
+    return EFI_UNSUPPORTED;
+  }
+  if (TargetNetworkInterface == NULL) {
+    return EFI_SUCCESS; // Return EFI_SUCCESS if no network interface is specified.
+  }
+
+  ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode(&mEfiRedfishDiscoverNetworkInterface);
+  while (TRUE) {
+    if (CompareMem((VOID *)&ThisNetworkInterface->MacAddress, &TargetNetworkInterface->MacAddress, ThisNetworkInterface->HwAddressSize) == 0) {
+      break;
+    }
+    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
+      return EFI_UNSUPPORTED;
+    }
+    ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
+  };
+  if ((Flags & EFI_REDFISH_DISCOVER_SSDP) != 0) {
+    // Validate if UDP4/6 is supported on the given network interface.
+    // SSDP is not supported.
+
+    return EFI_SUCCESS;
+  }
+  if (ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle == NULL) {
+    return EFI_UNSUPPORTED; // The required protocol on this network interface is not found.
+  }
+  return EFI_SUCCESS;
+}
+/**
+  This function returns number of network interface instance.
+
+  @retval UINTN  Number of network interface instances.
+**/
+UINTN
+NumberOfNetworkInterface (VOID)
+{
+  UINTN Num;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
+
+  if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
+    return 0;
+  }
+
+  Num = 1;
+  ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+  while (TRUE) {
+    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
+      break;
+    }
+    ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
+    Num ++;
+  };
+  return Num;
+}
+
+/**
+  This function checks the  IP version supported on this
+  netwoek interface.
+
+  @param[in]    ThisNetworkInterface   EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
+
+  @retval TRUE  Is IPv6, otherwise IPv4.
+
+**/
+BOOLEAN
+CheckIsIpVersion6 (
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface
+)
+{
+  if (ThisNetworkInterface->NetworkProtocolType == ProtocolTypeTcp6) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+  This function discover Redfish service through SMBIOS host interface.
+
+  @param[in]    Instance     EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
+
+  @retval EFI_SUCCESS        Redfish service is discovered through SMBIOS Host interface.
+  @retval Others             Fail to discover Redfish service throught SMBIOS host interface
+
+**/
+EFI_STATUS
+DiscoverRedfishHostInterface (IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance)
+{
+  EFI_STATUS Status;
+  REDFISH_OVER_IP_PROTOCOL_DATA *Data;
+  REDFISH_INTERFACE_DATA  *DeviceDescriptor;
+  CHAR8 UuidStr[sizeof"00000000-0000-0000-0000-000000000000" + 1];
+  CHAR16 Ipv6Str [sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1];
+  CHAR8 RedfishServiceLocateStr [sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1];
+  UINTN StrSize;
+  UINTN MacCompareStstus;
+  BOOLEAN IsHttps;
+
+  Data = NULL;
+  DeviceDescriptor = NULL;
+
+  if (mSmbios == NULL) {
+    Status = gBS->LocateProtocol(&gEfiSmbiosProtocolGuid, NULL, (VOID **)&mSmbios);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+  Status = RedfishGetHostInterfaceProtocolData (mSmbios, &DeviceDescriptor, &Data); // Search for SMBIOS type 42h
+  if (!EFI_ERROR (Status) && Data != NULL && DeviceDescriptor != NULL) {
+    //
+    // Chceck if we can reach out Redfish service using this network interface.
+    // Check with MAC address using Device Descroptor Data Device Type 04 and Type 05.
+    // Those two types of Redfish host interface device has MAC information.
+    //
+    if (DeviceDescriptor->DeviceType == REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2) {
+      MacCompareStstus = CompareMem(&Instance->NetworkInterface->MacAddress, &DeviceDescriptor->DeviceDescriptor.PciPcieDeviceV2.MacAddress, 6);
+    } else if (DeviceDescriptor->DeviceType == REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2){
+      MacCompareStstus = CompareMem(&Instance->NetworkInterface->MacAddress, &DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.MacAddress, 6);
+    } else {
+      return EFI_UNSUPPORTED;
+    }
+    if (MacCompareStstus != 0) {
+      return EFI_UNSUPPORTED;
+    }
+
+    if (Data->RedfishServiceIpAddressFormat == 1) {
+      IP4_COPY_ADDRESS ((VOID *)&Instance->TargetIpAddress.v4, (VOID *)Data->RedfishServiceIpAddress);
+    } else {
+      IP6_COPY_ADDRESS ((VOID *)&Instance->TargetIpAddress.v6, (VOID *)Data->RedfishServiceIpAddress);
+    }
+
+    if (Instance->HostIntfValidation) {
+      DEBUG ((DEBUG_ERROR,"%a:Send UPnP unicast SSDP to validate this Redfish Host Interface is not supported.\n", __FUNCTION__));
+      Status = EFI_UNSUPPORTED;
+    } else {
+      //
+      // Add this istance to list without detial information of Redfish
+      // service.
+      //
+      IsHttps = FALSE;
+      if (Data->RedfishServiceIpPort == 443) {
+        IsHttps = TRUE;
+      }
+      StrSize = sizeof(UuidStr);
+      AsciiSPrint(UuidStr, StrSize, "%g", &Data->ServiceUuid);
+      //
+      // Generate Redfish service location string.
+      //
+      if (Data->RedfishServiceIpAddressFormat == REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP6) {
+        NetLibIp6ToStr((IPv6_ADDRESS *)&Data->RedfishServiceIpAddress, Ipv6Str, sizeof (Ipv6Str));
+        if (Data->RedfishServiceIpPort == 0 || IsHttps == TRUE) {
+            AsciiSPrintUnicodeFormat (
+              RedfishServiceLocateStr,
+              sizeof (RedfishServiceLocateStr),
+              L"%s",
+              Ipv6Str
+            );
+        } else {
+            AsciiSPrintUnicodeFormat(
+              RedfishServiceLocateStr,
+              sizeof (RedfishServiceLocateStr),
+              L"[%s]:%d",
+              Ipv6Str,
+              Data->RedfishServiceIpPort
+            );
+        }
+      } else {
+        if (Data->RedfishServiceIpPort == 0 || IsHttps == TRUE) {
+          AsciiSPrint(
+            RedfishServiceLocateStr,
+            sizeof (RedfishServiceLocateStr),
+            "%d.%d.%d.%d",
+            Data->RedfishServiceIpAddress [0],
+            Data->RedfishServiceIpAddress [1],
+            Data->RedfishServiceIpAddress [2],
+            Data->RedfishServiceIpAddress [3]
+            );
+        } else {
+          AsciiSPrint(
+            RedfishServiceLocateStr,
+            sizeof (RedfishServiceLocateStr),
+            "%d.%d.%d.%d:%d",
+            Data->RedfishServiceIpAddress [0],
+            Data->RedfishServiceIpAddress [1],
+            Data->RedfishServiceIpAddress [2],
+            Data->RedfishServiceIpAddress [3],
+            Data->RedfishServiceIpPort
+            );
+        }
+       }
+      Status = AddAndSignalNewRedfishService (
+            Instance,
+            NULL,
+            RedfishServiceLocateStr,
+            UuidStr,
+            NULL,
+            NULL,
+            NULL,
+            NULL,
+            IsHttps
+            );
+    }
+  }
+  return Status;
+}
+
+/**
+  The function adds a new found Redfish service to internal list and
+  notify client.
+
+  @param[in]  Instance              EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
+  @param[in]  RedfishVersion        Redfish version.
+  @param[in]  RedfishLocation       Redfish location.
+  @param[in]  Uuid                  Service UUID string.
+  @param[in]  Os                    OS string.
+  @param[in]  OsVer                 OS version string.
+  @param[in]  Product               Product string.
+  @param[in]  ProductVer            Product verison string.
+  @param[in]  UseHttps              Redfish service requires secured connection.
+  @retval EFI_SUCCESS               Redfish service is added to list successfully.
+
+**/
+EFI_STATUS
+AddAndSignalNewRedfishService (
+  IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
+  IN UINTN *RedfishVersion OPTIONAL,
+  IN CHAR8 *RedfishLocation OPTIONAL,
+  IN CHAR8 *Uuid  OPTIONAL,
+  IN CHAR8 *Os  OPTIONAL,
+  IN CHAR8 *OsVer  OPTIONAL,
+  IN CHAR8 *Product  OPTIONAL,
+  IN CHAR8 *ProductVer  OPTIONAL,
+  IN BOOLEAN UseHttps
+  )
+{
+  BOOLEAN NewFound;
+  BOOLEAN InfoRefresh;
+  BOOLEAN RestExOpened;
+  BOOLEAN DeleteRestEx;
+  EFI_STATUS Status;
+  EFI_REDFISH_DISCOVERED_INTERNAL_LIST *DiscoveredList;
+  EFI_REDFISH_DISCOVERED_INSTANCE *DiscoveredInstance;
+  CHAR16 *Char16Uuid;
+  EFI_REST_EX_PROTOCOL *RestEx;
+  EFI_REST_EX_HTTP_CONFIG_DATA *RestExHttpConfigData;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NetworkInterface;
+
+  NewFound = TRUE;
+  InfoRefresh = FALSE;
+  Char16Uuid = NULL;
+  RestExOpened = FALSE;
+  DeleteRestEx = FALSE;
+
+  DEBUG ((DEBUG_INFO,"%a:Add this instance to Redfish instance list.\n", __FUNCTION__));
+
+  if (Uuid != NULL) {
+    Char16Uuid = (CHAR16 *)AllocateZeroPool(AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
+    AsciiStrToUnicodeStrS ((const CHAR8 *)Uuid, Char16Uuid, AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
+  }
+  DiscoveredList = NULL;
+  DiscoveredInstance = NULL;
+  RestExHttpConfigData = NULL;
+
+  NetworkInterface = Instance->NetworkInterface;
+  if (!IsListEmpty (&mRedfishInstanceList)) {
+    //
+    // Is this a duplicate redfish service.
+    //
+    DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetFirstNode (&mRedfishInstanceList);
+    NewFound = FALSE;
+    do {
+      if (Char16Uuid == NULL || DiscoveredList->Instance->Information.Uuid == NULL) {
+        //
+        // Check if this Redfish instance already found using IP addrress.
+        //
+        if (!CheckIsIpVersion6(NetworkInterface)) {
+          if (CompareMem ((VOID *)&Instance->TargetIpAddress.v4,
+                      (VOID *)&DiscoveredList->Instance->Information.RedfishHostIpAddress.v4,
+                      sizeof (EFI_IPv4_ADDRESS)
+                      ) == 0)
+          {
+            DiscoveredInstance = DiscoveredList->Instance;
+            if (DiscoveredList->Instance->Information.Uuid == NULL &&
+                Char16Uuid != NULL) {
+              InfoRefresh = TRUE;
+              DiscoveredInstance = DiscoveredList->Instance;
+              DEBUG((DEBUG_INFO,"*** This Redfish Service information refresh ***\n"));
+            }
+            break;
+          }
+        } else {
+          if (CompareMem ((VOID *)&Instance->TargetIpAddress.v6,
+                      (VOID *)&DiscoveredList->Instance->Information.RedfishHostIpAddress.v6,
+                      sizeof (EFI_IPv6_ADDRESS)
+                      ) == 0)
+          {
+            DiscoveredInstance = DiscoveredList->Instance;
+            break;
+          }
+        }
+      } else {
+        //
+        // Check if this Redfish instance already found using UUID.
+        //
+        if (StrCmp((const CHAR16 *)Char16Uuid, (const CHAR16 *)DiscoveredList->Instance->Information.Uuid) == 0) {
+          DiscoveredInstance = DiscoveredList->Instance;
+          break;
+        }
+      }
+      if (IsNodeAtEnd (&mRedfishInstanceList, &DiscoveredList->NextInstance)) {
+        NewFound = TRUE;
+        break;
+      }
+      DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetNextNode (&mRedfishInstanceList, &DiscoveredList->NextInstance);
+    } while (TRUE);
+  }
+  if (NewFound || InfoRefresh) {
+    if (!InfoRefresh) {
+      DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INTERNAL_LIST));
+      if (DiscoveredList == NULL) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+      InitializeListHead (&DiscoveredList->NextInstance);
+      DiscoveredInstance = (EFI_REDFISH_DISCOVERED_INSTANCE *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INSTANCE));
+      if (DiscoveredInstance == NULL) {
+        FreePool ((VOID *)DiscoveredList);
+        return EFI_OUT_OF_RESOURCES;
+      }
+    }
+    DEBUG ((DEBUG_INFO,"*** Redfish Service Information ***\n"));
+
+    DiscoveredInstance->Information.UseHttps = UseHttps;
+    if (RedfishVersion != NULL) {
+      DiscoveredInstance->Information.RedfishVersion = *RedfishVersion;
+      DEBUG ((DEBUG_INFO,"Redfish service version: %d.\n", DiscoveredInstance->Information.RedfishVersion));
+    }
+    if (RedfishLocation != NULL) {
+      DiscoveredInstance->Information.Location = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)RedfishLocation) * sizeof(CHAR16));
+      AsciiStrToUnicodeStrS ((const CHAR8 *)RedfishLocation, DiscoveredInstance->Information.Location, AsciiStrSize((const CHAR8 *)RedfishLocation) * sizeof(CHAR16));
+      DEBUG ((DEBUG_INFO,"Redfish service location: %s.\n", DiscoveredInstance->Information.Location));
+    }
+    if (Uuid != NULL) {
+      DiscoveredInstance->Information.Uuid = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
+      AsciiStrToUnicodeStrS ((const CHAR8 *)Uuid, DiscoveredInstance->Information.Uuid, AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
+      DEBUG ((DEBUG_INFO,"Service UUID: %s.\n", DiscoveredInstance->Information.Uuid));
+    }
+    if (Os != NULL) {
+      DiscoveredInstance->Information.Os = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)Os) * sizeof(CHAR16));
+      AsciiStrToUnicodeStrS ((const CHAR8 *)Os, DiscoveredInstance->Information.Os, AsciiStrSize((const CHAR8 *)Os) * sizeof(CHAR16));
+      DEBUG ((DEBUG_INFO,"Redfish service OS: %s, Version:%s.\n", DiscoveredInstance->Information.Os, DiscoveredInstance->Information.OsVersion));
+    }
+    if (OsVer != NULL) {
+      DiscoveredInstance->Information.OsVersion = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)OsVer) * sizeof(CHAR16));
+      AsciiStrToUnicodeStrS ((const CHAR8 *)OsVer, DiscoveredInstance->Information.OsVersion, AsciiStrSize((const CHAR8 *)OsVer) * sizeof(CHAR16));
+    }
+    if (Product != NULL && ProductVer != NULL) {
+      DiscoveredInstance->Information.Product = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)Product) * sizeof(CHAR16));
+      AsciiStrToUnicodeStrS ((const CHAR8 *)Product, DiscoveredInstance->Information.Product, AsciiStrSize((const CHAR8 *)Product) * sizeof(CHAR16));
+      DiscoveredInstance->Information.ProductVer = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)ProductVer) * sizeof(CHAR16));
+      AsciiStrToUnicodeStrS ((const CHAR8 *)ProductVer, DiscoveredInstance->Information.ProductVer, AsciiStrSize((const CHAR8 *)ProductVer) * sizeof(CHAR16));
+      DEBUG ((DEBUG_INFO,"Redfish service product: %s, Version:%s.\n", DiscoveredInstance->Information.Product, DiscoveredInstance->Information.ProductVer));
+    }
+
+    if (RedfishLocation == NULL) {
+      // This is the Redfish reported from SMBIOS 42h
+      // without validation.
+
+      IP4_COPY_ADDRESS((VOID *)&DiscoveredInstance->Information.RedfishHostIpAddress.v4, (VOID *)&Instance->TargetIpAddress.v4);
+    }
+    if (!InfoRefresh) {
+      DiscoveredList->Instance = DiscoveredInstance;
+      InsertTailList(&mRedfishInstanceList, &DiscoveredList->NextInstance);
+    }
+    DiscoveredInstance->Status = EFI_SUCCESS;
+  } else {
+    if (DiscoveredList != NULL) {
+      DEBUG((DEBUG_INFO,"*** This Redfish Service was already found ***\n"));
+      if (DiscoveredInstance->Information.Uuid != NULL) {
+        DEBUG((DEBUG_INFO,"Service UUID: %s.\n", DiscoveredInstance->Information.Uuid));
+      } else {
+        DEBUG((DEBUG_INFO,"Service UUID: unknown.\n"));
+      }
+    }
+  }
+  if (Char16Uuid != NULL) {
+    FreePool((VOID *)Char16Uuid);
+  }
+
+  Status = EFI_SUCCESS;
+  if (NewFound || InfoRefresh) {
+    //
+    // Build up EFI_REDFISH_DISCOVERED_LIST in token.
+    //
+    Instance->DiscoverToken->DiscoverList.NumberOfServiceFound = 1;
+    Instance->DiscoverToken->DiscoverList.RedfishInstances = DiscoveredInstance;
+    DiscoveredInstance->Status = EFI_SUCCESS;
+    if (!InfoRefresh) {
+      Status = CreateRestExInstance (Instance, Instance->DiscoverToken); // Create REST EX child.
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a:Can't create REST EX child instance.\n",__FUNCTION__));
+        goto ON_EXIT;
+      }
+      Status = gBS->OpenProtocol ( // Configure local host information.
+                  Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
+                  &gEfiRestExProtocolGuid,
+                  (VOID **)&RestEx,
+                  Instance->NetworkInterface->OpenDriverAgentHandle,
+                  Instance->NetworkInterface->OpenDriverControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+      if (EFI_ERROR (Status)) {
+        DeleteRestEx = TRUE;
+        goto ERROR_EXIT;
+      }
+      RestExOpened = TRUE;
+      RestExHttpConfigData = AllocateZeroPool (sizeof (EFI_REST_EX_HTTP_CONFIG_DATA));
+      if (RestExHttpConfigData == NULL) {
+        Status = EFI_OUT_OF_RESOURCES;
+        DeleteRestEx = TRUE;
+        goto EXIT_FREE_CONFIG_DATA;
+      }
+      RestExHttpConfigData->SendReceiveTimeout = 5000;
+      RestExHttpConfigData->HttpConfigData.HttpVersion = HttpVersion11;
+      RestExHttpConfigData->HttpConfigData.LocalAddressIsIPv6 = CheckIsIpVersion6(NetworkInterface);
+      if (RestExHttpConfigData->HttpConfigData.LocalAddressIsIPv6) {
+        RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node = AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT));
+        if (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node == NULL) {
+          Status = EFI_OUT_OF_RESOURCES;
+          goto EXIT_FREE_CONFIG_DATA;
+        }
+      } else {
+        RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node = AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT));
+        if (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node == NULL) {
+          Status = EFI_OUT_OF_RESOURCES;
+          goto EXIT_FREE_CONFIG_DATA;
+        }
+        RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node->UseDefaultAddress = TRUE;
+      }
+      Status = RestEx->Configure (
+                       RestEx,
+                       (EFI_REST_EX_CONFIG_DATA)(UINT8 *)RestExHttpConfigData
+                       );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR,"%a:REST EX configured..\n", __FUNCTION__));
+        DeleteRestEx = TRUE;
+        goto EXIT_FREE_ALL;
+      }
+      //
+      // Signal client, close REST EX before signaling client.
+      //
+      if (RestExOpened) {
+        gBS->CloseProtocol(
+             Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
+             &gEfiRestExProtocolGuid,
+             Instance->NetworkInterface->OpenDriverAgentHandle,
+             Instance->NetworkInterface->OpenDriverControllerHandle
+          );
+        RestExOpened = FALSE;
+      }
+    }
+    Status = gBS->SignalEvent(Instance->DiscoverToken->Event);
+    if (!EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR,"%a:No event to signal!\n", __FUNCTION__));
+    }
+  }
+
+EXIT_FREE_ALL:;
+  if (RestExHttpConfigData != NULL && RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node != NULL) {
+    FreePool (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node);
+  }
+
+EXIT_FREE_CONFIG_DATA:;
+  if (RestExHttpConfigData != NULL) {
+    FreePool((VOID *)RestExHttpConfigData);
+  }
+  if (RestExOpened) {
+    gBS->CloseProtocol(
+           Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
+           &gEfiRestExProtocolGuid,
+           Instance->NetworkInterface->OpenDriverAgentHandle,
+           Instance->NetworkInterface->OpenDriverControllerHandle
+        );
+  }
+ERROR_EXIT:;
+    if (DeleteRestEx && RestExOpened) {
+      gBS->CloseProtocol(
+           Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
+           &gEfiRestExProtocolGuid,
+           Instance->NetworkInterface->OpenDriverAgentHandle,
+           Instance->NetworkInterface->OpenDriverControllerHandle
+        );
+    }
+ON_EXIT:;
+  return Status;
+}
+
+/**
+  This function gets the subnet information of this network interface instance.
+  can discover Redfish service on it.
+
+  @param[in]    Instance     EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance.
+  @param[in]    ImageHandle  EFI Image handle request the network interface list.
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+NetworkInterfaceGetSubnetInfo (
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance,
+  IN EFI_HANDLE ImageHandle
+  )
+{
+  EFI_STATUS Status;
+  UINT32 ProtocolType;
+  UINT32 IPv6InfoIndex;
+  EFI_IP6_ADDRESS_INFO *ThisSubnetAddrInfoIPv6;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NewNetworkInterface;
+
+  if (Instance->GotSubnetInfo) {
+    return EFI_SUCCESS;
+  }
+
+  ProtocolType = Instance->NetworkProtocolType;
+  if (gRequiredProtocol [ProtocolType].GetSubnetInfo != NULL && Instance->GotSubnetInfo == FALSE) {
+    Status = gRequiredProtocol [ProtocolType].GetSubnetInfo (
+        ImageHandle,
+        Instance
+        );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR,"%a:Faile to get Subnet infomation.\n", __FUNCTION__));
+      return Status;
+    } else {
+      DEBUG ((DEBUG_INFO,"%a:MAC address: %s\n", __FUNCTION__, Instance->StrMacAddr));
+      if (CheckIsIpVersion6 (Instance)) {
+        if (Instance->SubnetAddrInfoIPv6Number == 0) {
+          DEBUG ((DEBUG_ERROR,"%a: There is no Subnet infomation for IPv6 network interface.\n", __FUNCTION__));
+          return EFI_NOT_FOUND;
+        }
+        ThisSubnetAddrInfoIPv6 = Instance->SubnetAddrInfoIPv6; // First IPv6 address information.
+        IP6_COPY_ADDRESS (&Instance->SubnetAddr.v6, &ThisSubnetAddrInfoIPv6->Address);
+        Instance->SubnetPrefixLength = ThisSubnetAddrInfoIPv6->PrefixLength;
+        DEBUG((DEBUG_INFO,"   IPv6 Subnet ID:%d, Prefix length: %d.\n",
+               ThisSubnetAddrInfoIPv6->Address.Addr [7] + (UINT16)ThisSubnetAddrInfoIPv6->Address.Addr [6] * 256,
+               ThisSubnetAddrInfoIPv6->PrefixLength)
+               );
+        //
+        // If this is IPv6, then we may have to propagate network interface for IPv6 network scopes
+        // according to the Ipv6 address information.
+        //
+        ThisSubnetAddrInfoIPv6 ++;
+        for (IPv6InfoIndex = 0; IPv6InfoIndex < Instance->SubnetAddrInfoIPv6Number - 1; IPv6InfoIndex++) {
+          //
+          // Build up addtional EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instances.
+          //
+          NewNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL));
+          if (NewNetworkInterface != NULL) {
+            CopyMem ((VOID *)NewNetworkInterface, (VOID *)Instance, sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL)); // Clone information of first instance.
+            IP6_COPY_ADDRESS (&NewNetworkInterface->SubnetAddr.v6, &ThisSubnetAddrInfoIPv6->Address);
+            NewNetworkInterface->SubnetPrefixLength = ThisSubnetAddrInfoIPv6->PrefixLength;
+            NewNetworkInterface->GotSubnetInfo = TRUE;
+            InsertTailList (&mEfiRedfishDiscoverNetworkInterface, &NewNetworkInterface->Entry);
+            ThisSubnetAddrInfoIPv6 ++;
+            mNumNetworkInterface ++;
+            DEBUG((DEBUG_INFO,"   IPv6 Subnet ID:%d, Prefix length: %d.\n",
+                   ThisSubnetAddrInfoIPv6->Address.Addr [7] + (UINT16)ThisSubnetAddrInfoIPv6->Address.Addr [6] * 256,
+                   ThisSubnetAddrInfoIPv6->PrefixLength)
+                  );
+          } else {
+            return EFI_OUT_OF_RESOURCES;
+          }
+        }
+      } else {
+        DEBUG ((DEBUG_INFO,"   IPv4 Subnet:%d.%d.%d.%d Subnet mask: %d.%d.%d.%d.\n",
+                    Instance->SubnetAddr.v4.Addr [0],
+                    Instance->SubnetAddr.v4.Addr [1],
+                    Instance->SubnetAddr.v4.Addr [2],
+                    Instance->SubnetAddr.v4.Addr [3],
+                    Instance->SubnetMask.v4.Addr [0],
+                    Instance->SubnetMask.v4.Addr [1],
+                    Instance->SubnetMask.v4.Addr [2],
+                    Instance->SubnetMask.v4.Addr [3]
+                    ));
+      }
+    }
+  }
+  Instance->GotSubnetInfo = TRUE; // Only try to get Subnet Info once.
+  return EFI_SUCCESS;
+}
+
+/**
+  This function gets the network interface list which Redfish discover protocol
+  can discover Redfish service on it.
+
+  @param[in]    This                  EFI_REDFISH_DISCOVER_PROTOCOL instance.
+  @param[in]    ImageHandle           EFI Image handle request the network interface list,
+  @param[out]   NumberOfNetworkIntfs  Number of network interfaces can do Redfish service discovery.
+  @param[out]   NetworkIntfInstances  Network interface instances. It's an array of instance. The number of entries
+                                      in array is indicated by NumberOfNetworkIntfs.
+                                      Caller has to release the memory
+                                      allocated by Redfish discover protocol.
+
+  @retval EFI_SUCCESS        The information of network interface is returned in NumberOfNetworkIntfs and
+                             NetworkIntfInstances.
+  @retval Others             Fail to return the information of network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishServiceGetNetworkInterface (
+  IN EFI_REDFISH_DISCOVER_PROTOCOL   *This,
+  IN EFI_HANDLE                      ImageHandle,
+  OUT UINTN                          *NumberOfNetworkIntfs,
+  OUT EFI_REDFISH_DISCOVER_NETWORK_INTERFACE **NetworkIntfInstances
+)
+{
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterfaceIntn;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *ThisNetworkInterface;
+
+  if (NetworkIntfInstances == NULL || NumberOfNetworkIntfs == NULL || ImageHandle == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *NumberOfNetworkIntfs = 0;
+  *NetworkIntfInstances = NULL;
+
+  if (IsListEmpty ((const LIST_ENTRY*)&mEfiRedfishDiscoverNetworkInterface)) {
+    return EFI_NOT_FOUND;
+  }
+
+  ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE) * mNumNetworkInterface);
+  if (ThisNetworkInterface == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  *NetworkIntfInstances = ThisNetworkInterface;
+  ThisNetworkInterfaceIntn = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+  while (TRUE) {
+    ThisNetworkInterface->IsIpv6 = FALSE;
+    if (CheckIsIpVersion6 (ThisNetworkInterfaceIntn)) {
+      ThisNetworkInterface->IsIpv6 = TRUE;
+    }
+    CopyMem((VOID *)&ThisNetworkInterface->MacAddress, &ThisNetworkInterfaceIntn->MacAddress, ThisNetworkInterfaceIntn->HwAddressSize);
+    NetworkInterfaceGetSubnetInfo(ThisNetworkInterfaceIntn, ImageHandle); // Get subnet info.
+    if (!ThisNetworkInterface->IsIpv6) {
+      IP4_COPY_ADDRESS(&ThisNetworkInterface->SubnetId.v4, &ThisNetworkInterfaceIntn->SubnetAddr.v4); // IPv4 subnet information.
+    } else {
+      IP6_COPY_ADDRESS (&ThisNetworkInterface->SubnetId.v6, &ThisNetworkInterfaceIntn->SubnetAddr.v6); // IPv6 subnet information in IPv6 address information.
+    }
+    ThisNetworkInterface->SubnetPrefixLength = ThisNetworkInterfaceIntn->SubnetPrefixLength;
+    ThisNetworkInterface->VlanId = ThisNetworkInterfaceIntn->VlanId;
+    (*NumberOfNetworkIntfs) ++;
+    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterfaceIntn->Entry)) {
+      break;
+    }
+    ThisNetworkInterfaceIntn = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterfaceIntn->Entry);
+    ThisNetworkInterface ++;
+  };
+  return EFI_SUCCESS;
+}
+/**
+  This function acquires Redfish services by discovering static Redfish setting
+  according to Redfish Host Interface or through SSDP. Returns a list of EFI
+  handles in EFI_REDFISH_DISCOVERED_LIST. Each of EFI handle has cooresponding
+  EFI REST EX instance installed on it. Each REST EX isntance is a child instance which
+  created through EFI REST EX serivce protoocl for communicating with specific
+  Redfish service.
+
+  @param[in]    This                    EFI_REDFISH_DISCOVER_PROTOCOL instance.
+  @param[in]    ImageHandle             EFI image owns these Redfish service instances.
+  @param[in]    TargetNetworkInterface  Target network interface to do the discovery.
+                                        NULL means discover Redfish service on all network interfaces on platform.
+  @param[in]    Flags                   Redfish service discover flags.
+  @param[in]    Token                   EFI_REDFISH_DISCOVERED_TOKEN instance.
+                                        The memory of EFI_REDFISH_DISCOVERED_LIST and the strings in
+                                        EFI_REDFISH_DISCOVERED_INFORMATION are all allocated by Acquire()
+                                        and must be freed when caller invoke Release().
+
+  @retval EFI_SUCCESS             REST EX instance of discovered Redfish services are returned.
+  @retval EFI_INVALID_PARAMETERS  ImageHandle == NULL, Flags == 0, Token == NULL, Token->Timeout > 5,
+                                  or Token->Event == NULL.
+  @retval Others                  Fail acquire Redfish services.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishServiceAcquireService (
+  IN EFI_REDFISH_DISCOVER_PROTOCOL          *This,
+  IN EFI_HANDLE                             ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE  *TargetNetworkInterface,
+  IN EFI_REDFISH_DISCOVER_FLAG              Flags,
+  IN EFI_REDFISH_DISCOVERED_TOKEN           *Token
+  )
+{
+  EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance;
+  EFI_STATUS Status1;
+  EFI_STATUS Status2;
+  BOOLEAN NewInstance;
+  UINTN NumNetworkInterfaces;
+  UINTN NetworkInterfacesIndex;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *TargetNetworkInterfaceInternal;
+
+  DEBUG ((DEBUG_INFO,"%a:Entry.\n", __FUNCTION__));
+
+  //
+  // Validate parameters.
+  //
+  if (ImageHandle == NULL || Token == NULL || ((Flags & ~EFI_REDFISH_DISCOVER_VALIDATION) == 0)) {
+    DEBUG ((DEBUG_ERROR,"%a:Invalid parameters.\n", __FUNCTION__));
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Validate target network interface.
+  //
+  if (EFI_ERROR (ValidateTargetNetworkInterface (TargetNetworkInterface, Flags))) {
+      return EFI_UNSUPPORTED;
+  }
+  if (TargetNetworkInterface != NULL) {
+    TargetNetworkInterfaceInternal = GetTargetNetworkInterfaceInternal (TargetNetworkInterface);
+    NumNetworkInterfaces = 1;
+  } else {
+    TargetNetworkInterfaceInternal = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+    NumNetworkInterfaces = NumberOfNetworkInterface ();
+    if (NumNetworkInterfaces == 0) {
+      DEBUG ((DEBUG_ERROR,"%a:No network interface on platform.\n", __FUNCTION__));
+      return EFI_UNSUPPORTED;
+    }
+  }
+  for (NetworkInterfacesIndex = 0; NetworkInterfacesIndex < NumNetworkInterfaces; NetworkInterfacesIndex ++) {
+    Status1 = EFI_SUCCESS;
+    Status2 = EFI_SUCCESS;
+    NewInstance = FALSE;
+    Instance = GetInstanceByOwner (ImageHandle, TargetNetworkInterfaceInternal, Flags & ~EFI_REDFISH_DISCOVER_VALIDATION); // Check if we can re-use previous instance.
+    if (Instance == NULL) {
+      DEBUG ((DEBUG_INFO,"%a:Create new EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.\n", __FUNCTION__));
+      Instance = (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE));
+      if (Instance == NULL) {
+        DEBUG ((DEBUG_ERROR,"%a:Memory allocation fail.\n", __FUNCTION__));
+      }
+      InitializeListHead (&Instance->Entry);
+      Instance->Owner = ImageHandle;
+      Instance->DiscoverFlags = Flags & ~EFI_REDFISH_DISCOVER_VALIDATION;
+      Instance->NetworkInterface = TargetNetworkInterfaceInternal;
+      //
+      // Get subnet information in case subnet information is not set because
+      // RedfishServiceGetNetworkInterfaces hasn't been called yet.
+      //
+      NetworkInterfaceGetSubnetInfo (TargetNetworkInterfaceInternal, ImageHandle);
+      NewInstance = TRUE;
+    }
+    if (TargetNetworkInterfaceInternal->StrMacAddr != NULL) {
+      DEBUG((DEBUG_INFO,"%a:Acquire Redfish service on network interface MAC address:%s.\n", __FUNCTION__, TargetNetworkInterfaceInternal->StrMacAddr));
+    } else {
+      DEBUG((DEBUG_INFO,"%a:WARNING: No MAC address on this network interface.\n", __FUNCTION__));
+    }
+
+    Instance->DiscoverToken = Token; // Always use the latest Token passed by caller.
+    if ((Flags & EFI_REDFISH_DISCOVER_HOST_INTERFACE) != 0) {
+      DEBUG ((DEBUG_INFO,"%a:Redfish HOST interface discovery.\n", __FUNCTION__));
+      Instance->HostIntfValidation = FALSE;
+      if ((Flags & EFI_REDFISH_DISCOVER_VALIDATION) != 0) {
+        Instance->HostIntfValidation = TRUE;
+      }
+      Status1 = DiscoverRedfishHostInterface (Instance); // Discover Redfish service through Redfish Host Interface.
+    }
+    if ((Flags & EFI_REDFISH_DISCOVER_SSDP) != 0) {
+      DEBUG ((DEBUG_ERROR,"%a:Redfish service discovery through SSDP is not supported\n", __FUNCTION__));
+      return EFI_UNSUPPORTED;
+    } else {
+      if (EFI_ERROR (Status1) && EFI_ERROR (Status2)) {
+        FreePool ((VOID *)Instance);
+        DEBUG ((DEBUG_ERROR,"%a:Something wrong on Redfish service discovery Status1=%x, Status2=%x.\n", __FUNCTION__, Status1, Status2));
+      } else {
+        if (NewInstance) {
+          InsertTailList(&mRedfishDiscoverList, &Instance->Entry);
+        }
+      }
+    }
+    if (TargetNetworkInterface == NULL) {
+      //
+      // Discover Redfish services on all of network interfaces.
+      //
+      TargetNetworkInterfaceInternal = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &TargetNetworkInterfaceInternal->Entry);
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  This function aborts Redfish service discovery on the given network interface.
+
+  @param[in]    This                    EFI_REDFISH_DISCOVER_PROTOCOL instance.
+  @param[in]    TargetNetworkInterface  Target network interface to do the discovery.
+
+  @retval EFI_SUCCESS             REST EX instance of discovered Redfish services are returned.
+  @retval Others                  Fail to abort Redfish service discovery.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishServiceAbortAcquire (
+  IN EFI_REDFISH_DISCOVER_PROTOCOL      *This,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE  *TargetNetworkInterface OPTIONAL
+)
+{
+  // This function is used to abort Redfish service discovery through SSDP
+  // on the network interface. SSDP is optionally supprted by EFI_REDFISH_DISCOVER_PROTOCOL,
+  // we dont have implementation for SSDP now.
+
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  This function releases Redfish services found by RedfishServiceAcquire().
+
+  @param[in]    This         EFI_REDFISH_DISCOVER_PROTOCOL instance.
+  @param[in]    InstanceList The Redfish service to release.
+
+  @retval EFI_SUCCESS        REST EX instances of discovered Redfish are released.
+  @retval Others             Fail to remove the entry
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishServiceReleaseService (
+  IN EFI_REDFISH_DISCOVER_PROTOCOL   *This,
+  IN EFI_REDFISH_DISCOVERED_LIST *InstanceList
+  )
+{
+  UINTN NumService;
+  BOOLEAN AnyFailRelease;
+  EFI_REDFISH_DISCOVERED_INSTANCE *ThisRedfishInstance;
+  EFI_REDFISH_DISCOVERED_INTERNAL_LIST *DiscoveredRedfishInstance;
+
+  if (IsListEmpty (&mRedfishInstanceList)) {
+    DEBUG ((DEBUG_ERROR,"%a:No any discovered Redfish service.\n", __FUNCTION__));
+    return EFI_NOT_FOUND;
+  }
+  AnyFailRelease = FALSE;
+  ThisRedfishInstance = InstanceList->RedfishInstances;
+  for (NumService = 0; NumService < InstanceList->NumberOfServiceFound; NumService ++) {
+    DiscoveredRedfishInstance = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetFirstNode(&mRedfishInstanceList);
+    do {
+      if (DiscoveredRedfishInstance->Instance == ThisRedfishInstance) {
+        RemoveEntryList (&DiscoveredRedfishInstance->NextInstance);
+        if (ThisRedfishInstance->Information.Location != NULL) {
+          FreePool (ThisRedfishInstance->Information.Location);
+        }
+        if (ThisRedfishInstance->Information.Uuid != NULL) {
+          FreePool (ThisRedfishInstance->Information.Uuid);
+        }
+        if (ThisRedfishInstance->Information.Os != NULL) {
+          FreePool (ThisRedfishInstance->Information.Os);
+        }
+        if (ThisRedfishInstance->Information.OsVersion != NULL) {
+          FreePool (ThisRedfishInstance->Information.OsVersion);
+        }
+        if (ThisRedfishInstance->Information.Product != NULL) {
+          FreePool (ThisRedfishInstance->Information.Product);
+        }
+        if (ThisRedfishInstance->Information.ProductVer != NULL) {
+          FreePool (ThisRedfishInstance->Information.ProductVer);
+        }
+        FreePool((VOID *)ThisRedfishInstance);
+        goto ReleaseNext;
+      }
+
+      if (IsNodeAtEnd(&mRedfishInstanceList, &DiscoveredRedfishInstance->NextInstance)) {
+        break;
+      }
+      DiscoveredRedfishInstance = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetNextNode(&mRedfishInstanceList, &DiscoveredRedfishInstance->NextInstance);
+    } while (TRUE);
+    AnyFailRelease = TRUE;
+ReleaseNext:;
+    //
+    // Release next discovered Redfish Service.
+    //
+    ThisRedfishInstance = (EFI_REDFISH_DISCOVERED_INSTANCE *)((UINT8 *)ThisRedfishInstance + sizeof (EFI_REDFISH_DISCOVERED_INSTANCE));
+  }
+  if (AnyFailRelease) {
+    return EFI_NOT_FOUND;
+  } else {
+    return EFI_SUCCESS;
+  }
+}
+
+EFI_REDFISH_DISCOVER_PROTOCOL mRedfishDiscover = {
+  RedfishServiceGetNetworkInterface,
+  RedfishServiceAcquireService,
+  RedfishServiceAbortAcquire,
+  RedfishServiceReleaseService
+};
+
+/**
+  This function create an EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL for the
+  given network interface.
+
+
+  @param[in]  ControllerHandle    MAC address of this network interface.
+  @param[in]  NetworkProtocolType Network protocol type.
+  @param[out] IsNewInstance       BOOLEAN means new instance or not.
+  @param[out] NetworkInterface    Pointer to to EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL.
+
+  @retval EFI_STATUS
+**/
+EFI_STATUS
+CreateRedfishDiscoverNetworkInterface (
+  IN EFI_HANDLE ControllerHandle,
+  IN UINT32 NetworkProtocolType,
+  OUT BOOLEAN  *IsNewInstance,
+  OUT EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL **NetworkInterface
+  )
+{
+  EFI_MAC_ADDRESS MacAddress;
+  UINTN HwAddressSize;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NewNetworkInterface;
+
+  NetLibGetMacAddress (ControllerHandle, &MacAddress, &HwAddressSize);
+  NewNetworkInterface = NULL;
+  *IsNewInstance = TRUE;
+  if (!IsListEmpty ((const LIST_ENTRY*)&mEfiRedfishDiscoverNetworkInterface)) {
+    //
+    // Check if this instance already exist.
+    //
+    ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+    if (ThisNetworkInterface != NULL) {
+      while (TRUE) {
+        if ((CompareMem ((CONST VOID *)&ThisNetworkInterface->MacAddress.Addr, (CONST VOID *)&MacAddress.Addr, HwAddressSize) == 0) &&
+             (ThisNetworkInterface->NetworkProtocolType == NetworkProtocolType)){
+          NewNetworkInterface = ThisNetworkInterface;
+          *IsNewInstance = FALSE;
+          break;
+        }
+        if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
+          NewNetworkInterface = NULL;
+          break;
+        }
+        ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
+      };
+    }
+  }
+  if (NewNetworkInterface == NULL) {
+    //
+    // Create a new instance.
+    //
+    NewNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL));
+    if (NewNetworkInterface == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    NewNetworkInterface->HwAddressSize = HwAddressSize;
+    CopyMem (&NewNetworkInterface->MacAddress.Addr, &MacAddress.Addr, NewNetworkInterface->HwAddressSize);
+    NetLibGetMacString (ControllerHandle, NULL, &NewNetworkInterface->StrMacAddr);
+    NewNetworkInterface->VlanId = NetLibGetVlanId (ControllerHandle);
+  }
+  *NetworkInterface = NewNetworkInterface;
+  return EFI_SUCCESS;
+}
+
+/**
+  This function destory network interface
+
+
+  @param[in]  ThisNetworkInterface EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance.
+
+  @retval EFI_STATUS
+**/
+EFI_STATUS
+DestroyRedfishNetwrokInterface (
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface
+  )
+{
+  EFI_STATUS Status;
+
+  Status = gBS->UninstallProtocolInterface(
+                  ThisNetworkInterface->OpenDriverControllerHandle,
+                  gRequiredProtocol [ThisNetworkInterface->NetworkProtocolType].DiscoveredProtocolGuid,
+                  &ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolDiscoverId
+                  );
+  RemoveEntryList (&ThisNetworkInterface->Entry);
+  mNumNetworkInterface --;
+  FreePool (ThisNetworkInterface);
+  return Status;
+}
+
+/**
+  Tests to see if the required protocols are provided on the given
+  controller handle.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @retval EFI_SUCCESS              One of required protocol is found.
+  @retval EFI_UNSUPPORTED          None of required protocol is found.
+**/
+EFI_STATUS
+TestForRequiredProtocols (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE ControllerHandle
+  )
+{
+  UINT32 Id;
+  UINTN Index;
+  EFI_STATUS Status;
+
+  for (Index = 0; Index < (sizeof (gRequiredProtocol) / sizeof (REDFISH_DISCOVER_REQUIRED_PROTOCOL)); Index ++) {
+    Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+    if (!EFI_ERROR (Status)) {
+      Status = gBS->OpenProtocol (
+                      ControllerHandle,
+                      gRequiredProtocol [Index].DiscoveredProtocolGuid,
+                      (VOID **) &Id,
+                      This->DriverBindingHandle,
+                      ControllerHandle,
+                      EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                      );
+      if (EFI_ERROR (Status)) {
+        DEBUG((DEBUG_ERROR, "%a: %s is found on this controller handle.\n", __FUNCTION__, gRequiredProtocol [Index].ProtocolName));
+        return EFI_SUCCESS;
+      }
+    }
+  }
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Build up network interface and create corresponding service through the given
+  controller handle.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @retval EFI_SUCCESS              One of required protocol is found.
+  @retval EFI_UNSUPPORTED          None of required protocol is found.
+  @retval EFI_UNSUPPORTED          Failed to build up network interface.
+**/
+EFI_STATUS
+BuildupNetworkInterface (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE ControllerHandle
+  )
+{
+  UINT32 Id;
+  UINT32 Index;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NetworkInterface;
+  BOOLEAN IsNew;
+  EFI_STATUS Status;
+  VOID *TempInterface;
+  VOID **Interface;
+  UINT32 *ProtocolDiscoverIdPtr;
+  EFI_HANDLE OpenDriverAgentHandle;
+  EFI_HANDLE OpenDriverControllerHandle;
+  EFI_HANDLE *HandleOfProtocolInterfacePtr;
+  EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *RestExInstance;
+  EFI_TPL OldTpl;
+  BOOLEAN NewNetworkInterfaceInstalled;
+
+  NewNetworkInterfaceInstalled = FALSE;
+  Index = 0;
+  do {
+    Status = gBS->OpenProtocol ( // Already in list?
+                    ControllerHandle,
+                    gRequiredProtocol [Index].DiscoveredProtocolGuid,
+                    (VOID **) &Id,
+                    This->DriverBindingHandle,
+                    ControllerHandle,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if (!EFI_ERROR (Status)) {
+      Index ++;
+      if (Index == (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
+        break;
+      }
+      continue;
+    }
+
+    Status = gBS->OpenProtocol (
+                    ControllerHandle,
+                    gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid,
+                    &TempInterface,
+                    This->DriverBindingHandle,
+                    ControllerHandle,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if (EFI_ERROR (Status)) {
+      Index ++;
+      if (Index == (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
+        break;
+      }
+      continue;
+    }
+    if (gRequiredProtocol [Index].ProtocolType != ProtocolTypeRestEx) {
+      OldTpl = gBS->RaiseTPL (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
+      Status = CreateRedfishDiscoverNetworkInterface(ControllerHandle, gRequiredProtocol [Index].ProtocolType, &IsNew, &NetworkInterface);
+      if (EFI_ERROR (Status)) {
+        gBS->RestoreTPL (OldTpl);
+        return Status;
+      }
+      NetworkInterface->NetworkProtocolType = gRequiredProtocol [Index].ProtocolType;
+      NetworkInterface->OpenDriverAgentHandle = This->DriverBindingHandle;
+      NetworkInterface->OpenDriverControllerHandle = ControllerHandle;
+      NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolGuid = \
+        *gRequiredProtocol [Index].RequiredProtocolGuid;
+      NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolServiceGuid = \
+        *gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid;
+      ProtocolDiscoverIdPtr = &NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolDiscoverId;
+      OpenDriverAgentHandle = NetworkInterface->OpenDriverAgentHandle;
+      OpenDriverControllerHandle = NetworkInterface->OpenDriverControllerHandle;
+      HandleOfProtocolInterfacePtr = &NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle;
+      Interface = &NetworkInterface->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
+      NewNetworkInterfaceInstalled = TRUE;
+      if (IsNew) {
+        InsertTailList (&mEfiRedfishDiscoverNetworkInterface, &NetworkInterface->Entry);
+        mNumNetworkInterface ++;
+      }
+      gBS->RestoreTPL (OldTpl);
+    } else {
+      // Record REST_EX instance. REST_EX is created when clinet asks for Redfish service discovery.
+      // Redfish Service Discover protocol will match REST EX to the corresponding EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
+      // when discovery.
+
+      RestExInstance = (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL));
+      if (RestExInstance == NULL) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+      RestExInstance->OpenDriverAgentHandle = This->DriverBindingHandle;
+      RestExInstance->OpenDriverControllerHandle = ControllerHandle;
+      RestExInstance->RestExControllerHandle = ControllerHandle;
+      InitializeListHead (&RestExInstance->Entry);
+      InsertTailList (&mEfiRedfishDiscoverRestExInstance, &RestExInstance->Entry);
+      mNumRestExInstance ++;
+      ProtocolDiscoverIdPtr = &RestExInstance->RestExId;
+      OpenDriverAgentHandle = RestExInstance->OpenDriverAgentHandle;
+      OpenDriverControllerHandle = RestExInstance->OpenDriverControllerHandle;
+      HandleOfProtocolInterfacePtr = &RestExInstance->RestExChildHandle;
+      Interface = (VOID **)&RestExInstance->RestExProtocolInterface;
+    }
+    Status = gBS->InstallProtocolInterface (
+                    &ControllerHandle,
+                    gRequiredProtocol [Index].DiscoveredProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    ProtocolDiscoverIdPtr
+                    );
+    if (EFI_ERROR (Status)) {
+      Index ++;
+      if (Index == (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
+        break;
+      }
+      continue;
+    }
+    //
+    // Create service binding child and open it BY_DRIVER.
+    //
+    Status = NetLibCreateServiceChild (
+              ControllerHandle,
+              This->ImageHandle,
+              gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid,
+              HandleOfProtocolInterfacePtr
+              );
+    if (!EFI_ERROR (Status)) {
+      Status = gBS->OpenProtocol (
+                    *HandleOfProtocolInterfacePtr,
+                    gRequiredProtocol [Index].RequiredProtocolGuid,
+                    Interface,
+                    OpenDriverAgentHandle,
+                    OpenDriverControllerHandle,
+                    EFI_OPEN_PROTOCOL_BY_DRIVER
+                    );
+      if (!EFI_ERROR (Status)) {
+        if (EfiRedfishDiscoverProtocolHandle == NULL &&
+            (gRequiredProtocol [Index].ProtocolType == ProtocolTypeRestEx) &&
+            !IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)
+            ) {
+          // Install the fisrt Redfish Discover Protocol when EFI REST EX protcol is discovered.
+          // This ensures EFI REST EX is ready while EFI_REDFISH_DISCOVER_PROTOCOL consumer acquires
+          // Redfish serivce over network interface.
+
+          Status = gBS->InstallProtocolInterface (
+                          &EfiRedfishDiscoverProtocolHandle,
+                          &gEfiRedfishDiscoverProtocolGuid,
+                          EFI_NATIVE_INTERFACE,
+                          (VOID *)&mRedfishDiscover
+                          );
+        } else if (EfiRedfishDiscoverProtocolHandle != NULL && NewNetworkInterfaceInstalled) {
+           Status = gBS->ReinstallProtocolInterface (
+                            EfiRedfishDiscoverProtocolHandle,
+                            &gEfiRedfishDiscoverProtocolGuid,
+                            (VOID *)&mRedfishDiscover,
+                            (VOID *)&mRedfishDiscover
+                            );
+           NewNetworkInterfaceInstalled = FALSE;
+        }
+      }
+      return Status;
+    } else {
+      Index ++;
+      if (Index == (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
+        break;
+      }
+      continue;
+    }
+  } while (Index < (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL)));
+  return EFI_UNSUPPORTED;
+}
+/**
+  Close the protocol opened for Redfish discovery. This function also destories
+  the network services.
+
+  @param[in]  ThisBindingProtocol     A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle        The handle of the controller to test. This handle
+                                      must support a protocol interface that supplies
+                                      an I/O abstraction to the driver.
+  @param[in]  ThisRequiredProtocol    Pointer to the instance of REDFISH_DISCOVER_REQUIRED_PROTOCOL.
+  @param[in]  DriverAgentHandle      Driver agent handle which used to open protocol earlier.
+  @param[in]  DriverControllerHandle Driver controller handle which used to open protocol earlier.
+
+  @retval EFI_SUCCESS                Prorocol is closed successfully.
+  @retval Others                     Prorocol is closed unsuccessfully.
+
+**/
+EFI_STATUS
+CloseProtocolService (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *ThisBindingProtocol,
+  IN EFI_HANDLE  ControllerHandle,
+  IN REDFISH_DISCOVER_REQUIRED_PROTOCOL *ThisRequiredProtocol,
+  IN EFI_HANDLE DriverAgentHandle,
+  IN EFI_HANDLE DriverControllerHandle
+)
+{
+  EFI_STATUS Status;
+
+  Status = gBS->CloseProtocol (
+                   ControllerHandle,
+                   ThisRequiredProtocol->RequiredProtocolGuid,
+                   DriverAgentHandle,
+                   DriverControllerHandle
+                   );
+  if (!EFI_ERROR (Status)) {
+    NetLibDestroyServiceChild(
+      ControllerHandle,
+      ThisBindingProtocol->ImageHandle,
+      ThisRequiredProtocol->RequiredServiceBindingProtocolGuid,
+      ControllerHandle
+      );
+  }
+  return Status;
+}
+/**
+  Stop the services on network interface.
+
+  @param[in]  ThisBindingProtocol  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @retval EFI_SUCCESS              One of required protocol is found.
+  @retval Others                   Faile to stop the services on network interface.
+**/
+EFI_STATUS
+StopServiceOnNetworkInterface (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *ThisBindingProtocol,
+  IN EFI_HANDLE ControllerHandle
+  )
+{
+  UINT32 Index;
+  EFI_STATUS Status;
+  VOID *Interface;
+  EFI_TPL OldTpl;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
+  EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *RestExInstance;
+
+  for (Index = 0; Index < (sizeof (gRequiredProtocol) / sizeof (REDFISH_DISCOVER_REQUIRED_PROTOCOL)); Index ++) {
+    Status = gBS->HandleProtocol (
+                  ControllerHandle,
+                  gRequiredProtocol [Index].RequiredProtocolGuid,
+                  (VOID **)&Interface
+                  );
+    if (!EFI_ERROR (Status)) {
+      if (gRequiredProtocol [Index].ProtocolType != ProtocolTypeRestEx) {
+        if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
+          return EFI_NOT_FOUND;
+        }
+        OldTpl = gBS->RaiseTPL (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
+        ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+        while (TRUE) {
+          if (ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle == ControllerHandle) {
+
+            Status = CloseProtocolService ( // Close protocol and destroy service.
+                       ThisBindingProtocol,
+                       ControllerHandle,
+                       &gRequiredProtocol [Index],
+                       ThisNetworkInterface->OpenDriverAgentHandle,
+                       ThisNetworkInterface->OpenDriverControllerHandle
+                       );
+            if (!EFI_ERROR (Status)) {
+              Status = DestroyRedfishNetwrokInterface (ThisNetworkInterface);
+            }
+            gBS->RestoreTPL (OldTpl);
+            // Reinstall Redfish Discover protocol to notify network
+            // interface change.
+
+            Status = gBS->ReinstallProtocolInterface (
+                            EfiRedfishDiscoverProtocolHandle,
+                            &gEfiRedfishDiscoverProtocolGuid,
+                            (VOID *)&mRedfishDiscover,
+                            (VOID *)&mRedfishDiscover
+                            );
+            if (EFI_ERROR (Status)) {
+              DEBUG((DEBUG_ERROR, "%a: Reinstall gEfiRedfishDiscoverProtocolGuid fail.", __FUNCTION__));
+            }
+            return Status;
+          }
+          if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
+            break;
+          }
+          ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
+        };
+        gBS->RestoreTPL (OldTpl);
+      } else {
+        if (IsListEmpty (&mEfiRedfishDiscoverRestExInstance)) {
+          return EFI_NOT_FOUND;
+        }
+        OldTpl = gBS->RaiseTPL (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
+        RestExInstance = (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverRestExInstance);
+        while (TRUE) {
+          if (RestExInstance->RestExChildHandle == ControllerHandle) {
+            Status = CloseProtocolService ( // Close REST_EX protocol.
+                       ThisBindingProtocol,
+                       ControllerHandle,
+                       &gRequiredProtocol [Index],
+                       RestExInstance->OpenDriverAgentHandle,
+                       RestExInstance->OpenDriverControllerHandle
+                       );
+            RemoveEntryList (&RestExInstance->Entry);
+            FreePool ((VOID *)RestExInstance);
+            mNumRestExInstance --;
+            gBS->RestoreTPL (OldTpl);
+            return Status;
+          }
+          if (IsNodeAtEnd (&mEfiRedfishDiscoverRestExInstance, &RestExInstance->Entry)) {
+            break;
+          }
+          RestExInstance = (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverRestExInstance, &RestExInstance->Entry);
+        };
+        gBS->RestoreTPL (OldTpl);
+      }
+    }
+  }
+  return EFI_NOT_FOUND;
+}
+/**
+  Tests to see if this driver supports a given controller. If a child device is provided,
+  it further tests to see if this driver supports creating a handle for the specified child device.
+
+  This function checks to see if the driver specified by This supports the device specified by
+  ControllerHandle. Drivers will typically use the device path attached to
+  ControllerHandle and/or the services from the bus I/O abstraction attached to
+  ControllerHandle to determine if the driver supports ControllerHandle. This function
+  may be called many times during platform initialization. In order to reduce boot times, the tests
+  performed by this function must be very small, and take as little time as possible to execute. This
+  function must not change the state of any hardware devices, and this function must be aware that the
+  device specified by ControllerHandle may already be managed by the same driver or a
+  different driver. This function must match its calls to AllocatePages() with FreePages(),
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required
+  to guarantee the state of ControllerHandle is not modified by this function.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
+                                   parameter is ignored by device drivers, and is optional for bus
+                                   drivers. For bus drivers, if this parameter is not NULL, then
+                                   the bus driver must determine if the bus controller specified
+                                   by ControllerHandle and the child controller specified
+                                   by RemainingDevicePath are both supported by this
+                                   bus driver.
+
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and
+                                   RemainingDevicePath is supported by the driver specified by This.
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed by the driver
+                                   specified by This.
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed by a different
+                                   driver or an application that requires exclusive access.
+                                   Currently not implemented.
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
+                                   RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  )
+{
+  return TestForRequiredProtocols (This, ControllerHandle);
+}
+
+/**
+  Starts a device controller or a bus controller.
+
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().
+  As a result, much of the error checking on the parameters to Start() has been moved into this
+  common boot service. It is legal to call Start() from other locations,
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE.
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+     EFI_DEVICE_PATH_PROTOCOL.
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
+                                   parameter is ignored by device drivers, and is optional for bus
+                                   drivers. For a bus driver, if this parameter is NULL, then handles
+                                   for all the children of Controller are created by this driver.
+                                   If this parameter is not NULL and the first Device Path Node is
+                                   not the End of Device Path Node, then only the handle for the
+                                   child device specified by the first Device Path Node of
+                                   RemainingDevicePath is created by this driver.
+                                   If the first Device Path Node of RemainingDevicePath is
+                                   the End of Device Path Node, no child handle is created by this
+                                   driver.
+
+  @retval EFI_SUCCESS              The device was started.
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
+  @retval Others                   The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  )
+{
+  return BuildupNetworkInterface (This, ControllerHandle);
+}
+
+/**
+  Stops a device controller or a bus controller.
+
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+  As a result, much of the error checking on the parameters to Stop() has been moved
+  into this common boot service. It is legal to call Stop() from other locations,
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+     same driver's Start() function.
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+     Start() function, and the Start() function must have called OpenProtocol() on
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
+                                support a bus specific I/O protocol for the driver
+                                to use to stop the device.
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
+                                if NumberOfChildren is 0.
+
+  @retval EFI_SUCCESS           The device was stopped.
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverDriverBindingStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN UINTN                        NumberOfChildren,
+  IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
+  )
+{
+  return StopServiceOnNetworkInterface (This, ControllerHandle);
+}
+
+EFI_DRIVER_BINDING_PROTOCOL gRedfishDiscoverDriverBinding = {
+  RedfishDiscoverDriverBindingSupported,
+  RedfishDiscoverDriverBindingStart,
+  RedfishDiscoverDriverBindingStop,
+  REDFISH_DISCOVER_VERSION,
+  NULL,
+  NULL
+};
+
+/**
+  This is the declaration of an EFI image entry point.
+
+  @param  ImageHandle           The firmware allocated handle for the UEFI image.
+  @param  SystemTable           A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval Others                An unexpected error occurred.
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS Status;
+
+  Status = EFI_SUCCESS;
+  InitializeListHead (&mRedfishDiscoverList);
+  InitializeListHead (&mRedfishInstanceList);
+  InitializeListHead (&mEfiRedfishDiscoverNetworkInterface);
+  InitializeListHead (&mEfiRedfishDiscoverRestExInstance);
+  //
+  // Install binding protoocl to obtain UDP and REST EX protocol.
+  //
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle,
+             SystemTable,
+             &gRedfishDiscoverDriverBinding,
+             ImageHandle,
+             &gRedfishDiscoverComponentName,
+             &gRedfishDiscoverComponentName2
+             );
+  return Status;
+}
+
+/**
+  This is the unload handle for Redfish discover module.
+
+  Disconnect the driver specified by ImageHandle from all the devices in the handle database.
+  Uninstall all the protocols installed in the driver entry point.
+
+  @param[in] ImageHandle           The drivers' driver image.
+
+  @retval    EFI_SUCCESS           The image is unloaded.
+  @retval    Others                Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverUnload (
+  IN EFI_HANDLE ImageHandle
+  )
+{
+  EFI_STATUS Status;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
+
+  Status = EFI_SUCCESS;
+  // Destroy all network interfaces found by EFI Redfish Discover driver and
+  // stop services created for Redfish Discover.
+
+  while (!IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
+    ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+    StopServiceOnNetworkInterface (&gRedfishDiscoverDriverBinding, ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle);
+  };
+  // Disconnect EFI Redfish discover driver controller to notify the
+  // clinet which uses .EFI Redfish discover protocol.
+
+  if (EfiRedfishDiscoverProtocolHandle != NULL) {
+    //
+    // Notify user EFI_REDFISH_DISCOVER_PROTOCOL is unloaded.
+    //
+    gBS->DisconnectController (EfiRedfishDiscoverProtocolHandle, NULL, NULL);
+    Status = gBS->UninstallProtocolInterface(
+                    EfiRedfishDiscoverProtocolHandle,
+                    &gEfiRedfishDiscoverProtocolGuid,
+                    (VOID *)&mRedfishDiscover
+                    );
+  }
+  return Status;
+}
diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c b/RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
new file mode 100644
index 0000000000..f3ad36ec3a
--- /dev/null
+++ b/RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
@@ -0,0 +1,118 @@
+/** @file
+  RedfishSmbiosHostInterface.c
+
+  Discover Redfish SMBIOS Host Interface.
+
+  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishDiscoverInternal.h"
+
+SMBIOS_TABLE_TYPE42  *mType42Record;
+
+/**
+  The function gets information reported in Redfish Host Interface.
+
+  It simply frees the packet.
+
+  @param[in]  Smbios           SMBIOS protocol.
+  @param[out] DeviceDescriptor Pointer to REDFISH_INTERFACE_DATA.
+  @param[out] ProtocolData     Pointer to REDFISH_OVER_IP_PROTOCOL_DATA.
+
+  @retval EFI_SUCCESS    Get host interface succesfully.
+  @retval Otherwise      Fail to tet host interface.
+
+**/
+EFI_STATUS
+RedfishGetHostInterfaceProtocolData (
+  IN EFI_SMBIOS_PROTOCOL              *Smbios,
+  OUT REDFISH_INTERFACE_DATA          **DeviceDescriptor,
+  OUT REDFISH_OVER_IP_PROTOCOL_DATA   **ProtocolData
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_SMBIOS_HANDLE                 SmbiosHandle;
+  EFI_SMBIOS_TABLE_HEADER           *Record;
+  UINT16                            Offset;
+  UINT8                             *RecordTmp;
+  UINT8                             ProtocolLength;
+  UINT8                             SpecificDataLen;
+
+  if ((Smbios == NULL) || (ProtocolData == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
+  Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
+  while (!EFI_ERROR (Status) && SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED) {
+    if (Record->Type == SMBIOS_TYPE_MANAGEMENT_CONTROLLER_HOST_INTERFACE) {
+      //
+      // Check Interface Type, should be Network Host Interface = 40h
+      //
+      mType42Record = (SMBIOS_TABLE_TYPE42 *) Record;
+      if (mType42Record->InterfaceType == MCHostInterfaceTypeNetworkHostInterface) {
+        ASSERT (Record->Length >= 9);
+        Offset = 5;
+        RecordTmp = (UINT8 *) Record + Offset;
+        //
+        // Get interface specific data length.
+        //
+        SpecificDataLen = *RecordTmp;
+        Offset += 1;
+        RecordTmp = (UINT8 *) Record + Offset;
+
+        //
+        // Check Device Type, only PCI/PCIe Network Interface v2 is supported now.
+        //
+        if (*RecordTmp == REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2) {
+          ASSERT (SpecificDataLen == sizeof (PCI_OR_PCIE_INTERFACE_DEVICE_DESCRIPTOR_V2) + 1);
+          *DeviceDescriptor = (REDFISH_INTERFACE_DATA *)RecordTmp;
+          Offset = Offset + SpecificDataLen;
+          RecordTmp = (UINT8 *) Record + Offset;
+          //
+          // Check Protocol count. if > 1, only use the first protocol.
+          //
+          ASSERT (*RecordTmp == 1);
+          Offset += 1;
+          RecordTmp = (UINT8 *) Record + Offset;
+          //
+          // Check protocol identifier.
+          //
+          if (*RecordTmp == MCHostInterfaceProtocolTypeRedfishOverIP) {
+            Offset += 1;
+            RecordTmp = (UINT8 *) Record + Offset;
+            ProtocolLength = *RecordTmp;
+
+            Offset += 1;
+            RecordTmp = (UINT8 *) Record + Offset;
+
+            //
+            // This SMBIOS record is invalid, if the length of protocol specific data for
+            // Redfish Over IP protocol is wrong.
+            //
+            if ((*(RecordTmp + 90) + sizeof (REDFISH_OVER_IP_PROTOCOL_DATA) - 1) != ProtocolLength) {
+              return EFI_SECURITY_VIOLATION;
+            }
+
+            Offset += ProtocolLength;
+            //
+            // This SMBIOS record is invalid, if the length is smaller than the offset.
+            //
+            if (Offset > mType42Record->Hdr.Length) {
+              return EFI_SECURITY_VIOLATION;
+            }
+            *ProtocolData = (REDFISH_OVER_IP_PROTOCOL_DATA *)RecordTmp;
+            return EFI_SUCCESS;
+          }
+        }
+      }
+    }
+    Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
+  }
+
+  *ProtocolData = NULL;
+  return EFI_NOT_FOUND;
+}
-- 
2.17.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#73308): https://edk2.groups.io/g/devel/message/73308
Mute This Topic: https://groups.io/mt/81621784/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-


回复: [edk2-devel] [PATCH] RedfishPkg/RedfishDiscoverDxe: EFI Redfish Discover Protocol
Posted by gaoliming 3 years ago
Abner:
  This is new feature. Can you submit one BZ for it?

Thanks
Liming
> -----邮件原件-----
> 发件人: devel@edk2.groups.io <devel@edk2.groups.io> 代表 Abner Chang
> 发送时间: 2021年3月26日 12:54
> 收件人: devel@edk2.groups.io
> 抄送: Nickle Wang <nickle.wang@hpe.com>; Jiaxin Wu
> <jiaxin.wu@intel.com>; Siyuan Fu <siyuan.fu@intel.com>; Fan Wang
> <fan.wang@intel.com>; Jiewen Yao <jiewen.yao@intel.com>
> 主题: [edk2-devel] [PATCH] RedfishPkg/RedfishDiscoverDxe: EFI Redfish
> Discover Protocol
> 
> EDK2 EFI Redfish Discover Protocol implementation. Refer to UEFI spec 2.9
> section 31.1.
> 
> Signed-off-by: Abner Chang <abner.chang@hpe.com>
> Cc: Nickle Wang <nickle.wang@hpe.com>
> Cc: Jiaxin Wu <jiaxin.wu@intel.com>
> Cc: Siyuan Fu <siyuan.fu@intel.com>
> Cc: Fan Wang <fan.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> ---
>  RedfishPkg/RedfishComponents.dsc.inc          |    3 +-
>  RedfishPkg/Redfish.fdf.inc                    |    3 +-
>  .../RedfishDiscoverDxe/RedfishDiscoverDxe.inf |   55 +
>  .../RedfishDiscoverInternal.h                 |  234 ++
>  RedfishPkg/RedfishDiscoverDxe/ComponentName.c |  218 ++
>  .../RedfishDiscoverDxe/RedfishDiscoverDxe.c   | 1910
> +++++++++++++++++
>  .../RedfishSmbiosHostInterface.c              |  118 +
>  7 files changed, 2539 insertions(+), 2 deletions(-)
>  create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
>  create mode 100644
> RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
>  create mode 100644 RedfishPkg/RedfishDiscoverDxe/ComponentName.c
>  create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
>  create mode 100644
> RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
> 
> diff --git a/RedfishPkg/RedfishComponents.dsc.inc
> b/RedfishPkg/RedfishComponents.dsc.inc
> index 08f1d3bc32..6f3b055aba 100644
> --- a/RedfishPkg/RedfishComponents.dsc.inc
> +++ b/RedfishPkg/RedfishComponents.dsc.inc
> @@ -6,7 +6,7 @@
>  # of EDKII Redfish drivers according to the value of flags described in
>  # "RedfishDefines.dsc.inc".
>  #
> -# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
> +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
>  #
>  #    SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
> @@ -17,4 +17,5 @@
>    RedfishPkg/RedfishHostInterfaceDxe/RedfishHostInterfaceDxe.inf
>    RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf
>    RedfishPkg/RedfishCredentialDxe/RedfishCredentialDxe.inf
> +  RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
>  !endif
> diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc
> index a64fd119a9..205c3101c0 100644
> --- a/RedfishPkg/Redfish.fdf.inc
> +++ b/RedfishPkg/Redfish.fdf.inc
> @@ -5,7 +5,7 @@
>  # by using "!include RedfishPkg/RedfisLibs.fdf.inc" to specify the module
> instances
>  # to be built in the firmware volume.
>  #
> -# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
> +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
>  #
>  #    SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
> @@ -15,4 +15,5 @@
>    INF RedfishPkg/RedfishHostInterfaceDxe/RedfishHostInterfaceDxe.inf
>    INF RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf
>    INF RedfishPkg/RedfishCredentialDxe/RedfishCredentialDxe.inf
> +  INF RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
>  !endif
> diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
> b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
> new file mode 100644
> index 0000000000..345bacf44d
> --- /dev/null
> +++ b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
> @@ -0,0 +1,55 @@
> +## @file
> +#  Implementation of EFI_REDFISH_DISCOVER_PROTOCOL interfaces.
> +#
> +#  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION               = 0x0001001b
> +  BASE_NAME                 = RedfishDiscoverDxe
> +  FILE_GUID                 =
> 28A76FE5-43D7-48A3-9714-C1B7BDD6DFB6
> +  MODULE_TYPE               = UEFI_DRIVER
> +  VERSION_STRING            = 1.0
> +  ENTRY_POINT               = RedfishDiscoverEntryPoint
> +  UNLOAD_IMAGE              = RedfishDiscoverUnload
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  NetworkPkg/NetworkPkg.dec
> +  RedfishPkg/RedfishPkg.dec
> +
> +[Sources]
> +  ComponentName.c
> +  RedfishDiscoverDxe.c
> +  RedfishSmbiosHostInterface.c
> +  RedfishDiscoverInternal.h
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  MemoryAllocationLib
> +  PrintLib
> +  RestExLib
> +  UefiLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +
> +[Protocols]
> +  gEfiRestExServiceBindingProtocolGuid            ## Consuming
> +  gEfiRestExProtocolGuid                          ## Consuming
> +  gEfiTcp4ServiceBindingProtocolGuid              ## Consuming
> +  gEfiTcp4ProtocolGuid                            ## Consuming
> +  gEfiTcp6ServiceBindingProtocolGuid              ## Consuming
> +  gEfiTcp6ProtocolGuid                            ## Consuming
> +  gEfiRedfishDiscoverProtocolGuid                 ## Prodcuing
> +  gEfiSmbiosProtocolGuid                          ## Consuming
> +  gEfiDriverBindingProtocolGuid                   ## Consuming
> +
> +[Pcd]
> +  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishDiscoverAccessModeInBand ##
> CONSUMES
> +
> diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
> b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
> new file mode 100644
> index 0000000000..cf69d9231a
> --- /dev/null
> +++ b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
> @@ -0,0 +1,234 @@
> +/** @file
> +  This file defines the EFI Redfish Discover Protocol interface.
> +
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef EFI_REDFISH_DISCOVER_INTERNAL_H_
> +#define EFI_REDFISH_DISCOVER_INTERNAL_H_
> +
> +#include <Uefi.h>
> +
> +#include <Protocol/ComponentName.h>
> +#include <Protocol/ComponentName2.h>
> +#include <Protocol/DriverBinding.h>
> +#include <Protocol/RedfishDiscover.h>
> +#include <Protocol/Smbios.h>
> +#include <Protocol/Tcp4.h>
> +#include <Protocol/Tcp6.h>
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/NetLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/RestExLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiDriverEntryPoint.h>
> +
> +#include <IndustryStandard/RedfishHostInterface.h>
> +
> +#define REDFISH_DISCOVER_VERSION  0x00010000
> +#define EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL TPL_NOTIFY
> +
> +//
> +//GUID definitions
> +//
> +
> +#define EFI_REDFISH_DISCOVER_TCP4_INSTANCE_GUID \
> +  { \
> +    0xfbab97a4, 0x4c6a, 0xf8e8, { 0xf2, 0x25, 0x42, 0x8a, 0x80, 0x3f,
0xb6,
> 0xaa } \
> +  }
> +
> +#define EFI_REDFISH_DISCOVER_TCP6_INSTANCE_GUID \
> +  { \
> +    0xbe513b6d, 0x41c1, 0x96Ed, { 0x8d, 0xaf, 0x3e, 0x89, 0xc5, 0xf5,
0x02,
> 0x25 } \
> +  }
> +
> +#define EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_GUID \
> +  { \
> +    0xc44a6076, 0xd42a, 0x4d54, { 0x85, 0x6d, 0x98, 0x8a, 0x85, 0x8f,
0xa1,
> 0x11 } \
> +  }
> +
> +extern EFI_COMPONENT_NAME_PROTOCOL
> gRedfishDiscoverComponentName;
> +extern EFI_COMPONENT_NAME2_PROTOCOL
> gRedfishDiscoverComponentName2;
> +extern EFI_UNICODE_STRING_TABLE
> *gRedfishDiscoverControllerNameTable;
> +
> +//
> +// Enumeration of network protocols
> +// required for the Redfish service discovery.
> +//
> +typedef enum {
> +  ProtocolTypeTcp4 = 0, ///< Network protocol TCPv4.
> +  ProtocolTypeTcp6,     ///< Network protocol TCCv6.
> +  ProtocolTypeRestEx,   ///< REST EX over network protocol.
> +  MaxProtocolType
> +} NETWORK_INTERFACE_PROTOCOL_TYPE;
> +
> +//
> +// Network protocol information installed on
> +// the network interface.
> +//
> +typedef struct {
> +  EFI_GUID ProtocolGuid;                ///< Network protocol GUID.
> +  EFI_GUID ProtocolServiceGuid;         ///< Network protocol service
> GUID.
> +  UINT32   ProtocolDiscoverId;          ///< The identifier installed on
> network protocol handle.
> +  EFI_HANDLE ProtocolControllerHandle;  ///< The controller handle on
> network protocol.
> +  VOID *NetworkProtocolInterface;       ///< The protocol interface of
> network protocol.
> +} REDFISH_DISCOVER_NETWORK_INTERFACE_PROTOCOL;
> +
> +//
> +// Internal structure used to maintain network
> +// interface properties.
> +//
> +typedef struct {
> +  LIST_ENTRY      Entry;                        ///< Link list
> entry.
> +  EFI_HANDLE      OpenDriverAgentHandle;        ///< The agent to
> open network protocol.
> +  EFI_HANDLE      OpenDriverControllerHandle;   ///< The controller
> handle to open network protocol.
> +  UINTN           HwAddressSize;                ///< The size of
> network interface hardware address.
> +  EFI_MAC_ADDRESS MacAddress;                   ///< MAC
> address of network interface.
> +  CHAR16          *StrMacAddr;                  ///< String to
> MAC address of network interface.
> +  BOOLEAN         GotSubnetInfo;                ///< Indicates sub
> net information is retrieved.
> +  EFI_IP_ADDRESS  SubnetAddr;                   ///< Subnet ID.
> +  EFI_IP_ADDRESS  SubnetMask;                   ///< Subnet mask
> (IPv4 only)
> +  UINT8           SubnetPrefixLength;           ///< Subnet prefix.
> +  UINT16          VlanId;                       ///< VLAN ID
> +  UINT32          SubnetAddrInfoIPv6Number;     ///< IPv6 address
> info number.
> +  EFI_IP6_ADDRESS_INFO *SubnetAddrInfoIPv6;     ///< IPv6 address
> info.
> +  //
> +  // Network interface protocol and REST EX infor.
> +  //
> +  UINT32          NetworkProtocolType;          ///< Network
> protocol type. Refer to
> +                                                ///<
> NETWORK_INTERFACE_PROTOCOL_TYPE.
> +  REDFISH_DISCOVER_NETWORK_INTERFACE_PROTOCOL
> NetworkInterfaceProtocolInfo; ///< Network interface protocol information.
> +  EFI_HANDLE      RestExHandle;                 ///< REST EX
> handle associated with this network interface.
> +} EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL;
> +
> +//
> +// Internal structure used to maintain REST EX properties.
> +//
> +typedef struct {
> +    LIST_ENTRY      Entry;                          ///< Link list
> entry.
> +    EFI_HANDLE      OpenDriverAgentHandle;          ///< The
> agent to open network protocol.
> +    EFI_HANDLE      OpenDriverControllerHandle;     ///< The
> controller handle to open network protocol.
> +    EFI_HANDLE      RestExChildHandle;              ///< The child
> handle created throught REST EX Service Protocol.
> +    EFI_HANDLE      RestExControllerHandle;         ///< The
> controller handle which provide REST EX protocol.
> +    EFI_REST_EX_PROTOCOL *RestExProtocolInterface;  ///< Pointer to
> EFI_REST_EX_PROTOCOL.
> +    UINT32          RestExId;                       ///< The
> identifier installed on REST EX controller handle.
> +} EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL;
> +
> +/**
> +  This function to get subnet information.
> +
> +  @param[in]            ImageHandle  EFI handle with this image.
> +  @param[in]            Instance  Instance of Network interface.
> +  @retval EFI_STATUS    Get subnet information successfully.
> +  @retval Otherwise     Fail to get subnet information.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EFI_REDFISH_DISCOVER_GET_SUBNET_INFO)(
> +  IN EFI_HANDLE ImageHandle,
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
> +);
> +
> +//
> +// The require network protocol matrix.
> +//
> +typedef struct {
> +  UINT32   ProtocolType;                                ///<
> Network protocol type,
> +                                                        ///<
> Refer to NETWORK_INTERFACE_PROTOCOL_TYPE.
> +  CHAR16   *ProtocolName;                               ///<
> Protocol name.
> +  EFI_GUID *RequiredProtocolGuid;                       ///<
> Network protocol interface GUID.
> +  EFI_GUID *RequiredServiceBindingProtocolGuid;         ///< Network
> protocol service GUID.
> +  EFI_GUID *DiscoveredProtocolGuid;                     ///<
> Protocol interface GUID use to install identifier.
> +  EFI_REDFISH_DISCOVER_GET_SUBNET_INFO GetSubnetInfo;   ///<
> Function of getting subnet information.
> +} REDFISH_DISCOVER_REQUIRED_PROTOCOL;
> +
> +//
> +// Link list of Redfish discover instance.
> +//
> +typedef struct {
> +  LIST_ENTRY  NextInstance;                             ///<
> Next list.
> +  EFI_REDFISH_DISCOVERED_INSTANCE *Instance;            ///<
> Pointer to EFI_REDFISH_DISCOVERED_INSTANCE.
> +} EFI_REDFISH_DISCOVERED_INTERNAL_LIST;
> +
> +//
> +// Internal structure of Redfish discover instance.
> +//
> +typedef struct {
> +  LIST_ENTRY  Entry;                                    ///<
> Link list entry.
> +  EFI_HANDLE  Owner;                                    ///<
> The owner owns this Redfish service discovery.
> +                                                        ///<
> It's the EFI image handle of driver uses
> +                                                        ///<
> EFI Redfish Discover Protocol.
> +  EFI_REDFISH_DISCOVER_FLAG DiscoverFlags;              ///<
> EFI_REDFISH_DISCOVER_FLAG
> +  EFI_REDFISH_DISCOVERED_TOKEN *DiscoverToken;          ///<
> Token used to signal when Redfish service is discovered.
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *NetworkInterface; ///<
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> +
> ///< instance used to discover Redfish service.
> +  //
> +  // Below for Host insterface discovery.
> +  //
> +  BOOLEAN         HostIntfValidation;                   ///<
> Indicates whether to validate Redfish Host interface.
> +  EFI_IP_ADDRESS  TargetIpAddress;                      ///<
> Target IP address reported in Redfish Host interface.
> +} EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE;
> +
> +/**
> +  The function adds a new foudn Redfish service to internal list and
> +  notify clinet.
> +
> +  It simply frees the packet.
> +
> +  @param[in]  Instance
> EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
> +  @param[in]  RedfishVersion        Redfish version.
> +  @param[in]  RedfishLocation       Redfish location.
> +  @param[in]  Uuid                  Service UUID string.
> +  @param[in]  Os                    OS string.
> +  @param[in]  OsVer                 OS version string.
> +  @param[in]  Product               Product string.
> +  @param[in]  ProductVer            Product verison string.
> +  @param[in]  UseHttps              Redfish service requires secured
> connection.
> +  @retval EFI_SUCCESS               Redfish service is added to list
> successfully.
> +
> +**/
> +EFI_STATUS
> +AddAndSignalNewRedfishService (
> +  IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
> +  IN UINTN *RedfishVersion OPTIONAL,
> +  IN CHAR8 *RedfishLocation OPTIONAL,
> +  IN CHAR8 *Uuid  OPTIONAL,
> +  IN CHAR8 *Os  OPTIONAL,
> +  IN CHAR8 *OsVer  OPTIONAL,
> +  IN CHAR8 *Product  OPTIONAL,
> +  IN CHAR8 *ProductVer  OPTIONAL,
> +  IN BOOLEAN UseHttps
> +  );
> +
> +/**
> +  The function gets information reported in Redfish Host Interface.
> +
> +  It simply frees the packet.
> +
> +  @param[in]  Smbios           SMBIOS protocol.
> +  @param[out] DeviceDescriptor Pointer to REDFISH_INTERFACE_DATA.
> +  @param[out] ProtocolData     Pointer to
> REDFISH_OVER_IP_PROTOCOL_DATA.
> +
> +  @retval EFI_SUCCESS    Get host interface succesfully.
> +  @retval Otherwise      Fail to tet host interface.
> +
> +**/
> +EFI_STATUS
> +RedfishGetHostInterfaceProtocolData (
> +  IN EFI_SMBIOS_PROTOCOL              *Smbios,
> +  OUT REDFISH_INTERFACE_DATA          **DeviceDescriptor,
> +  OUT REDFISH_OVER_IP_PROTOCOL_DATA   **ProtocolData
> +  );
> +
> +extern EFI_GUID gRedfishDiscoverTcp4Instance;
> +extern EFI_GUID gRedfishDiscoverTcp6Instance;
> +extern EFI_GUID gRedfishDiscoverRestEXInstance;
> +#endif
> diff --git a/RedfishPkg/RedfishDiscoverDxe/ComponentName.c
> b/RedfishPkg/RedfishDiscoverDxe/ComponentName.c
> new file mode 100644
> index 0000000000..adad2504bc
> --- /dev/null
> +++ b/RedfishPkg/RedfishDiscoverDxe/ComponentName.c
> @@ -0,0 +1,218 @@
> +/** @file
> +  Implementation of EFI_COMPONENT_NAME_PROTOCOL and
> EFI_COMPONENT_NAME2_PROTOCOL protocol.
> +  for EFI Refish Discover Protocol
> +
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "RedfishDiscoverInternal.h"
> +
> +//
> +// EFI Component Name Functions
> +//
> +/**
> +  Retrieves a Unicode string that is the user-readable name of the EFI
> Driver.
> +
> +  @param[in]  This       A pointer to the
> EFI_COMPONENT_NAME_PROTOCOL instance.
> +  @param[in]  Language   A pointer to a three-character ISO 639-2
> language identifier.
> +                         This is the language of the driver name that
> that the caller
> +                         is requesting, and it must match one of the
> languages specified
> +                         in SupportedLanguages.  The number of
> languages supported by a
> +                         driver is up to the driver writer.
> +  @param[out] DriverName A pointer to the Unicode string to return.
> This Unicode string
> +                         is the name of the driver specified by This in
> the language
> +                         specified by Language.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the Driver
> specified by This
> +                                and the language specified by
> Language was returned
> +                                in DriverName.
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> support the
> +                                language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishDiscoverComponentNameGetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> +  IN  CHAR8                        *Language,
> +  OUT CHAR16                       **DriverName
> +  );
> +
> +/**
> +  Retrieves a Unicode string that is the user readable name of the
controller
> +  that is being managed by an EFI Driver.
> +
> +  @param[in]  This             A pointer to the
> EFI_COMPONENT_NAME_PROTOCOL instance.
> +  @param[in]  ControllerHandle The handle of a controller that the driver
> specified by
> +                               This is managing.  This handle
> specifies the controller
> +                               whose name is to be returned.
> +  @param[in]  ChildHandle      The handle of the child controller to
> retrieve the name
> +                               of.  This is an optional parameter
> that may be NULL.  It
> +                               will be NULL for device drivers.  It
> will also be NULL
> +                               for a bus drivers that wish to retrieve
> the name of the
> +                               bus controller.  It will not be NULL
> for a bus driver
> +                               that wishes to retrieve the name of a
> child controller.
> +  @param[in]  Language         A pointer to a three character ISO
> 639-2 language
> +                               identifier.  This is the language of the
> controller name
> +                               that the caller is requesting, and it
> must match one
> +                               of the languages specified in
> SupportedLanguages.  The
> +                               number of languages supported by a
> driver is up to the
> +                               driver writer.
> +  @param[out]  ControllerName  A pointer to the Unicode string to
> return.  This Unicode
> +                               string is the name of the controller
> specified by
> +                               ControllerHandle and ChildHandle in
> the language specified
> +                               by Language, from the point of view
> of the driver specified
> +                               by This.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the
> user-readable name in the
> +                                language specified by Language for
> the driver
> +                                specified by This was returned in
> DriverName.
> +  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> valid EFI_HANDLE.
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> +  @retval EFI_UNSUPPORTED       The driver specified by This is not
> currently managing
> +                                the controller specified by
> ControllerHandle and
> +                                ChildHandle.
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> support the
> +                                language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishDiscoverComponentNameGetControllerName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> +  IN  EFI_HANDLE                    ControllerHandle,
> +  IN  EFI_HANDLE                    ChildHandle
> OPTIONAL,
> +  IN  CHAR8                         *Language,
> +  OUT CHAR16                        **ControllerName
> +  );
> +
> +
> +///
> +/// Component Name Protocol instance
> +///
> +GLOBAL_REMOVE_IF_UNREFERENCED
> +EFI_COMPONENT_NAME_PROTOCOL  gRedfishDiscoverComponentName
> = {
> +  RedfishDiscoverComponentNameGetDriverName,
> +  RedfishDiscoverComponentNameGetControllerName,
> +  "eng"
> +};
> +
> +///
> +/// Component Name 2 Protocol instance
> +///
> +GLOBAL_REMOVE_IF_UNREFERENCED
> +EFI_COMPONENT_NAME2_PROTOCOL
> gRedfishDiscoverComponentName2 = {
> +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)
> RedfishDiscoverComponentNameGetDriverName,
> +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)
> RedfishDiscoverComponentNameGetControllerName,
> +  "en"
> +};
> +
> +///
> +/// Table of driver names
> +///
> +GLOBAL_REMOVE_IF_UNREFERENCED
> +EFI_UNICODE_STRING_TABLE mRedfishDiscoverDriverNameTable[] = {
> +  { "eng;en", (CHAR16 *)L"Redfish Discover UEFI Driver" },
> +  { NULL, NULL }
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> *gRedfishDiscoverControllerNameTable = NULL;
> +
> +/**
> +  Retrieves a Unicode string that is the user-readable name of the EFI
> Driver.
> +
> +  @param[in]  This        A pointer to the
> EFI_COMPONENT_NAME_PROTOCOL instance.
> +  @param[in]  Language    A pointer to a three-character ISO 639-2
> language identifier.
> +                          This is the language of the driver name that
> that the caller
> +                          is requesting, and it must match one of the
> languages specified
> +                          in SupportedLanguages.  The number of
> languages supported by a
> +                          driver is up to the driver writer.
> +  @param[out]  DriverName A pointer to the Unicode string to return.
> This Unicode string
> +                          is the name of the driver specified by This in
> the language
> +                          specified by Language.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the Driver
> specified by This
> +                                and the language specified by
> Language was returned
> +                                in DriverName.
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> support the
> +                                language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishDiscoverComponentNameGetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> +  IN  CHAR8                        *Language,
> +  OUT CHAR16                       **DriverName
> +  )
> +{
> +  return LookupUnicodeString2 (
> +           Language,
> +           This->SupportedLanguages,
> +           mRedfishDiscoverDriverNameTable,
> +           DriverName,
> +           (BOOLEAN)(This == &gRedfishDiscoverComponentName)
> +           );
> +}
> +
> +/**
> +  Retrieves a Unicode string that is the user readable name of the
controller
> +  that is being managed by an EFI Driver.
> +
> +  @param[in]  This             A pointer to the
> EFI_COMPONENT_NAME_PROTOCOL instance.
> +  @param[in]  ControllerHandle The handle of a controller that the driver
> specified by
> +                               This is managing.  This handle
> specifies the controller
> +                               whose name is to be returned.
> +  @param[in]  ChildHandle      The handle of the child controller to
> retrieve the name
> +                               of.  This is an optional parameter
> that may be NULL.  It
> +                               will be NULL for device drivers.  It
> will also be NULL
> +                               for a bus drivers that wish to retrieve
> the name of the
> +                               bus controller.  It will not be NULL
> for a bus driver
> +                               that wishes to retrieve the name of a
> child controller.
> +  @param[in]  Language         A pointer to a three character ISO
> 639-2 language
> +                               identifier.  This is the language of the
> controller name
> +                               that the caller is requesting, and it
> must match one
> +                               of the languages specified in
> SupportedLanguages.  The
> +                               number of languages supported by a
> driver is up to the
> +                              driver writer.
> +  @param[out]  ControllerName  A pointer to the Unicode string to
> return.  This Unicode
> +                               string is the name of the controller
> specified by
> +                               ControllerHandle and ChildHandle in
> the language specified
> +                               by Language, from the point of view
> of the driver specified
> +                               by This.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the
> user-readable name in the
> +                                language specified by Language for
> the driver
> +                                specified by This was returned in
> DriverName.
> +  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> valid EFI_HANDLE.
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> +  @retval EFI_UNSUPPORTED       The driver specified by This is not
> currently managing
> +                                the controller specified by
> ControllerHandle and
> +                                ChildHandle.
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> support the
> +                                language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishDiscoverComponentNameGetControllerName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> +  IN  EFI_HANDLE                    ControllerHandle,
> +  IN  EFI_HANDLE                    ChildHandle
> OPTIONAL,
> +  IN  CHAR8                         *Language,
> +  OUT CHAR16                        **ControllerName
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
> b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
> new file mode 100644
> index 0000000000..80d70a4679
> --- /dev/null
> +++ b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
> @@ -0,0 +1,1910 @@
> +/** @file
> +
> +  The implementation of EFI Redfidh Discover Protocol.
> +
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "RedfishDiscoverInternal.h"
> +
> +LIST_ENTRY mRedfishDiscoverList;
> +LIST_ENTRY mRedfishInstanceList;
> +EFI_SMBIOS_PROTOCOL *mSmbios = NULL;
> +
> +UINTN mNumNetworkInterface = 0;
> +UINTN mNumRestExInstance = 0;
> +LIST_ENTRY mEfiRedfishDiscoverNetworkInterface;
> +LIST_ENTRY mEfiRedfishDiscoverRestExInstance;
> +
> +EFI_GUID mRedfishDiscoverTcp4InstanceGuid =
> EFI_REDFISH_DISCOVER_TCP4_INSTANCE_GUID;
> +EFI_GUID mRedfishDiscoverTcp6InstanceGuid =
> EFI_REDFISH_DISCOVER_TCP6_INSTANCE_GUID;
> +EFI_GUID mRedfishDiscoverRestExInstanceGuid =
> EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_GUID;
> +
> +EFI_HANDLE EfiRedfishDiscoverProtocolHandle = NULL;
> +
> +EFI_STATUS
> +EFIAPI
> +Tcp4GetSubnetInfo (
> +  IN EFI_HANDLE ImageHandle,
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
> +);
> +
> +EFI_STATUS
> +EFIAPI
> +Tcp6GetSubnetInfo (
> +  IN EFI_HANDLE ImageHandle,
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
> +);
> +
> +static REDFISH_DISCOVER_REQUIRED_PROTOCOL gRequiredProtocol[] = {
> +  {
> +    ProtocolTypeTcp4,
> +    L"TCP4 Service Binding Protocol",
> +    &gEfiTcp4ProtocolGuid,
> +    &gEfiTcp4ServiceBindingProtocolGuid,
> +    &mRedfishDiscoverTcp4InstanceGuid,
> +    Tcp4GetSubnetInfo
> +  },
> +  {
> +    ProtocolTypeTcp6,
> +    L"TCP6 Service Binding Protocol",
> +    &gEfiTcp6ProtocolGuid,
> +    &gEfiTcp6ServiceBindingProtocolGuid,
> +    &mRedfishDiscoverTcp6InstanceGuid,
> +    Tcp6GetSubnetInfo
> +  },
> +  {
> +    ProtocolTypeRestEx,
> +    L"REST EX Service Binding Protocol",
> +    &gEfiRestExProtocolGuid,
> +    &gEfiRestExServiceBindingProtocolGuid,
> +    &mRedfishDiscoverRestExInstanceGuid,
> +    NULL
> +  }
> +};
> +
> +/**
> +  This function creates REST EX instance for the found Resfish service.
> +  by known owner handle.
> +
> +  @param[in]    Instance
> EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
> +  @param[in]    Token           Client token.
> +
> +  @retval NULL  Instance not found.
> +  @retval EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE The instance
> owned by this owner.
> +
> +**/
> +EFI_STATUS
> +CreateRestExInstance (
> +  IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
> +  IN EFI_REDFISH_DISCOVERED_TOKEN *Token
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status = RestExLibCreateChild (
> +            Instance->Owner,
> +            FixedPcdGetBool (PcdRedfishDiscoverAccessModeInBand)?
> EfiRestExServiceInBandAccess: EfiRestExServiceOutOfBandAccess,
> +            EfiRestExConfigHttp,
> +            EfiRestExServiceRedfish,
> +
> &Token->DiscoverList.RedfishInstances->Information.RedfishRestExHandle
> +            );
> +  return Status;
> +}
> +
> +/**
> +  This function gets EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
> +  by known owner handle.
> +
> +  @param[in]    ImageHandle             Image handle owns
> EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
> +  @param[in]    TargetNetworkInterface  Target network interface used
> by this EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
> +  @param[in]    DiscoverFlags
> EFI_REDFISH_DISCOVER_FLAG
> +
> +  @retval NULL  Instance not found.
> +  @retval EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE The instance
> owned by this owner.
> +
> +**/
> +EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *
> +GetInstanceByOwner (
> +  IN EFI_HANDLE ImageHandle,
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *TargetNetworkInterface,
> +  IN EFI_REDFISH_DISCOVER_FLAG DiscoverFlags
> +  )
> +{
> +  EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *ThisInstance;
> +
> +  if (IsListEmpty (&mRedfishDiscoverList)) {
> +    return NULL;
> +  }
> +  ThisInstance =
> +    (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)GetFirstNode
> (&mRedfishDiscoverList);
> +  while (TRUE) {
> +    if ((ThisInstance->Owner == ImageHandle) &&
> +         (ThisInstance->DiscoverFlags == DiscoverFlags) &&
> +         (ThisInstance->NetworkInterface == TargetNetworkInterface)) {
> +      return ThisInstance;
> +    }
> +    if (IsNodeAtEnd (&mRedfishDiscoverList, &ThisInstance->Entry)) {
> +      break;
> +    }
> +    ThisInstance =
> +      (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)GetNextNode
> (&mRedfishDiscoverList, &ThisInstance->Entry);
> +  };
> +  return NULL;
> +}
> +
> +/**
> +  This function gets the subnet information of this TCP4 instance.
> +
> +  @param[in]            ImageHandle  EFI handle with this image.
> +  @param[in]            Instance  Instance of Network interface.
> +  @retval EFI_STATUS    Get subnet information successfully.
> +  @retval Otherwise     Fail to get subnet information.
> +**/
> +EFI_STATUS
> +EFIAPI
> +Tcp4GetSubnetInfo (
> +  IN EFI_HANDLE ImageHandle,
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
> +)
> +{
> +  EFI_STATUS Status;
> +  EFI_TCP4_PROTOCOL *Tcp4;
> +  EFI_TCP4_CONFIG_DATA Tcp4CfgData;
> +  EFI_TCP4_OPTION Tcp4Option;
> +  EFI_IP4_MODE_DATA IpModedata;
> +  UINT8 SubnetMaskIndex;
> +  UINT8 BitMask;
> +  UINT8 PrefixLength;
> +  BOOLEAN GotPrefixLength;
> +
> +  if (Instance == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  Tcp4 = (EFI_TCP4_PROTOCOL
> *)Instance->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
> +
> +  ZeroMem ((VOID *)&Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
> +  ZeroMem ((VOID *)&Tcp4Option, sizeof (EFI_TCP4_OPTION));
> +  // Give a local host IP address just for getting subnet information.
> +  Tcp4CfgData.AccessPoint.UseDefaultAddress = TRUE;
> +  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [0] = 127;
> +  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [1] = 0;
> +  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [2] = 0;
> +  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [3] = 1;
> +  Tcp4CfgData.AccessPoint.RemotePort  = 80;
> +  Tcp4CfgData.AccessPoint.ActiveFlag  = TRUE;
> +
> +  Tcp4CfgData.ControlOption = &Tcp4Option;
> +  Tcp4Option.ReceiveBufferSize      = 65535;
> +  Tcp4Option.SendBufferSize         = 65535;
> +  Tcp4Option.MaxSynBackLog          = 5;
> +  Tcp4Option.ConnectionTimeout      = 60;
> +  Tcp4Option.DataRetries            = 12;
> +  Tcp4Option.FinTimeout             = 2;
> +  Tcp4Option.KeepAliveProbes        = 6;
> +  Tcp4Option.KeepAliveTime          = 7200;
> +  Tcp4Option.KeepAliveInterval      = 30;
> +  Tcp4Option.EnableNagle            = TRUE;
> +  Status = Tcp4->Configure (Tcp4, &Tcp4CfgData);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: Can't get subnet information\n",
> __FUNCTION__));
> +    return Status;
> +  }
> +  Status = Tcp4->GetModeData (Tcp4, NULL, NULL, &IpModedata, NULL,
> NULL);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: Can't get IP mode data information\n",
> __FUNCTION__));
> +    return Status;
> +  }
> +  IP4_COPY_ADDRESS (&Instance->SubnetMask,
> &IpModedata.ConfigData.SubnetMask);
> +  Instance->SubnetAddr.v4.Addr [0] =
> IpModedata.ConfigData.StationAddress.Addr [0] &
> Instance->SubnetMask.v4.Addr [0];
> +  Instance->SubnetAddr.v4.Addr [1] =
> IpModedata.ConfigData.StationAddress.Addr [1] &
> Instance->SubnetMask.v4.Addr [1];
> +  Instance->SubnetAddr.v4.Addr [2] =
> IpModedata.ConfigData.StationAddress.Addr [2] &
> Instance->SubnetMask.v4.Addr [2];
> +  Instance->SubnetAddr.v4.Addr [3] =
> IpModedata.ConfigData.StationAddress.Addr [3] &
> Instance->SubnetMask.v4.Addr [3];
> +  //
> +  // Calculate the subnet mask prefix.
> +  //
> +  GotPrefixLength = FALSE;
> +  PrefixLength = 0;
> +  SubnetMaskIndex = 0;
> +  while (GotPrefixLength == FALSE && SubnetMaskIndex < 4) {
> +    BitMask = 0x80;
> +    while (BitMask != 0) {
> +      if ((Instance->SubnetMask.v4.Addr [SubnetMaskIndex] & BitMask) !=
> 0) {
> +        PrefixLength ++;
> +      } else {
> +        GotPrefixLength = TRUE;
> +        break;
> +      }
> +      BitMask = BitMask >> 1;
> +    };
> +    SubnetMaskIndex ++;
> +  };
> +  Instance->SubnetPrefixLength = PrefixLength;
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function gets the subnet information of this TCP6 instance.
> +
> +  @param[in]            ImageHandle  EFI handle with this image.
> +  @param[in]            Instance  Instance of Network interface.
> +  @retval EFI_STATUS    Get subnet information successfully.
> +  @retval Otherwise     Fail to get subnet information.
> +**/
> +EFI_STATUS
> +EFIAPI
> +Tcp6GetSubnetInfo (
> +  IN EFI_HANDLE ImageHandle,
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
> +)
> +{
> +  EFI_STATUS Status;
> +  EFI_TCP6_PROTOCOL *Tcp6;
> +  EFI_IP6_MODE_DATA IpModedata;
> +
> +  if (Instance == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  Tcp6 = (EFI_TCP6_PROTOCOL
> *)Instance->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
> +
> +  Status = Tcp6->GetModeData (Tcp6, NULL, NULL, &IpModedata, NULL,
> NULL);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: Can't get IP mode data information\n"));
> +    return Status;
> +  }
> +  if (IpModedata.AddressCount == 0) {
> +    DEBUG ((DEBUG_INFO, "%a: No IPv6 address configured.\n"));
> +  }
> +  if (Instance->SubnetAddrInfoIPv6 != NULL) {
> +    FreePool (Instance->SubnetAddrInfoIPv6);
> +  }
> +  Instance->SubnetAddrInfoIPv6 = AllocateZeroPool
> (IpModedata.AddressCount * sizeof (EFI_IP6_ADDRESS_INFO));
> +  if (Instance->SubnetAddrInfoIPv6 == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a: Failed to allocate memory fir IPv6
> subnet address information\n"));
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +  Instance->SubnetAddrInfoIPv6Number = IpModedata.AddressCount;
> +  CopyMem (
> +    (VOID *)Instance->SubnetAddrInfoIPv6,
> +    (VOID *)&IpModedata.AddressList,
> +    IpModedata.AddressCount * sizeof (EFI_IP6_ADDRESS_INFO)
> +    );
> +  FreePool (IpModedata.AddressList);
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function searches
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> +  instance with the given
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
> +
> +  @param[in] TargetNetworkInterface
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
> +                                     NULL for all
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACEs.
> +
> +  @retval Non-NULL
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL is returned.
> +  @retval NULL      Non of
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance is
> returned.
> +**/
> +EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *
> +GetTargetNetworkInterfaceInternal (
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE
> *TargetNetworkInterface
> +  )
> +{
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *ThisNetworkInterface;
> +
> +  ThisNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode
> (&mEfiRedfishDiscoverNetworkInterface);
> +  while (TRUE) {
> +    if (CompareMem((VOID *)&ThisNetworkInterface->MacAddress,
> &TargetNetworkInterface->MacAddress,
> ThisNetworkInterface->HwAddressSize) == 0) {
> +      return ThisNetworkInterface;
> +    }
> +    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface,
> &ThisNetworkInterface->Entry)) {
> +      return NULL;
> +    }
> +    ThisNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> &ThisNetworkInterface->Entry);
> +  };
> +  return NULL;
> +}
> +
> +/**
> +  This function validate if target network interface is ready for
discovering
> +  Redfish service.
> +
> +  @param[in] TargetNetworkInterface
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
> +                                     NULL for all
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACEs.
> +  @param[in] Flags                   EFI_REDFISH_DISCOVER_FLAG
> +
> +  @retval EFI_SUCCESS     Target network interface is ready to use.
> +  @retval EFI_UNSUPPORTED Target network interface is not ready to use.
> +**/
> +EFI_STATUS
> +ValidateTargetNetworkInterface (
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE
> *TargetNetworkInterface,
> +  IN EFI_REDFISH_DISCOVER_FLAG Flags
> +  )
> +{
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *ThisNetworkInterface;
> +
> +  if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface) &&
> TargetNetworkInterface == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +  if (TargetNetworkInterface == NULL) {
> +    return EFI_SUCCESS; // Return EFI_SUCCESS if no network interface is
> specified.
> +  }
> +
> +  ThisNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetFirstNode(&mEfiRedfishDiscoverNetworkInterface);
> +  while (TRUE) {
> +    if (CompareMem((VOID *)&ThisNetworkInterface->MacAddress,
> &TargetNetworkInterface->MacAddress,
> ThisNetworkInterface->HwAddressSize) == 0) {
> +      break;
> +    }
> +    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface,
> &ThisNetworkInterface->Entry)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +    ThisNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> &ThisNetworkInterface->Entry);
> +  };
> +  if ((Flags & EFI_REDFISH_DISCOVER_SSDP) != 0) {
> +    // Validate if UDP4/6 is supported on the given network interface.
> +    // SSDP is not supported.
> +
> +    return EFI_SUCCESS;
> +  }
> +  if
> (ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHan
> dle == NULL) {
> +    return EFI_UNSUPPORTED; // The required protocol on this network
> interface is not found.
> +  }
> +  return EFI_SUCCESS;
> +}
> +/**
> +  This function returns number of network interface instance.
> +
> +  @retval UINTN  Number of network interface instances.
> +**/
> +UINTN
> +NumberOfNetworkInterface (VOID)
> +{
> +  UINTN Num;
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *ThisNetworkInterface;
> +
> +  if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
> +    return 0;
> +  }
> +
> +  Num = 1;
> +  ThisNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode
> (&mEfiRedfishDiscoverNetworkInterface);
> +  while (TRUE) {
> +    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface,
> &ThisNetworkInterface->Entry)) {
> +      break;
> +    }
> +    ThisNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> &ThisNetworkInterface->Entry);
> +    Num ++;
> +  };
> +  return Num;
> +}
> +
> +/**
> +  This function checks the  IP version supported on this
> +  netwoek interface.
> +
> +  @param[in]    ThisNetworkInterface
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> +
> +  @retval TRUE  Is IPv6, otherwise IPv4.
> +
> +**/
> +BOOLEAN
> +CheckIsIpVersion6 (
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *ThisNetworkInterface
> +)
> +{
> +  if (ThisNetworkInterface->NetworkProtocolType == ProtocolTypeTcp6) {
> +    return TRUE;
> +  }
> +  return FALSE;
> +}
> +
> +/**
> +  This function discover Redfish service through SMBIOS host interface.
> +
> +  @param[in]    Instance
> EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
> +
> +  @retval EFI_SUCCESS        Redfish service is discovered through
> SMBIOS Host interface.
> +  @retval Others             Fail to discover Redfish service throught
> SMBIOS host interface
> +
> +**/
> +EFI_STATUS
> +DiscoverRedfishHostInterface (IN
> EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance)
> +{
> +  EFI_STATUS Status;
> +  REDFISH_OVER_IP_PROTOCOL_DATA *Data;
> +  REDFISH_INTERFACE_DATA  *DeviceDescriptor;
> +  CHAR8 UuidStr[sizeof"00000000-0000-0000-0000-000000000000" + 1];
> +  CHAR16 Ipv6Str [sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1];
> +  CHAR8 RedfishServiceLocateStr
[sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1];
> +  UINTN StrSize;
> +  UINTN MacCompareStstus;
> +  BOOLEAN IsHttps;
> +
> +  Data = NULL;
> +  DeviceDescriptor = NULL;
> +
> +  if (mSmbios == NULL) {
> +    Status = gBS->LocateProtocol(&gEfiSmbiosProtocolGuid, NULL, (VOID
> **)&mSmbios);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +  }
> +  Status = RedfishGetHostInterfaceProtocolData (mSmbios,
> &DeviceDescriptor, &Data); // Search for SMBIOS type 42h
> +  if (!EFI_ERROR (Status) && Data != NULL && DeviceDescriptor != NULL) {
> +    //
> +    // Chceck if we can reach out Redfish service using this network
> interface.
> +    // Check with MAC address using Device Descroptor Data Device Type
> 04 and Type 05.
> +    // Those two types of Redfish host interface device has MAC
> information.
> +    //
> +    if (DeviceDescriptor->DeviceType ==
> REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2) {
> +      MacCompareStstus =
> CompareMem(&Instance->NetworkInterface->MacAddress,
> &DeviceDescriptor->DeviceDescriptor.PciPcieDeviceV2.MacAddress, 6);
> +    } else if (DeviceDescriptor->DeviceType ==
> REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2){
> +      MacCompareStstus =
> CompareMem(&Instance->NetworkInterface->MacAddress,
> &DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.MacAddress, 6);
> +    } else {
> +      return EFI_UNSUPPORTED;
> +    }
> +    if (MacCompareStstus != 0) {
> +      return EFI_UNSUPPORTED;
> +    }
> +
> +    if (Data->RedfishServiceIpAddressFormat == 1) {
> +      IP4_COPY_ADDRESS ((VOID *)&Instance->TargetIpAddress.v4, (VOID
> *)Data->RedfishServiceIpAddress);
> +    } else {
> +      IP6_COPY_ADDRESS ((VOID *)&Instance->TargetIpAddress.v6, (VOID
> *)Data->RedfishServiceIpAddress);
> +    }
> +
> +    if (Instance->HostIntfValidation) {
> +      DEBUG ((DEBUG_ERROR,"%a:Send UPnP unicast SSDP to validate
> this Redfish Host Interface is not supported.\n", __FUNCTION__));
> +      Status = EFI_UNSUPPORTED;
> +    } else {
> +      //
> +      // Add this istance to list without detial information of Redfish
> +      // service.
> +      //
> +      IsHttps = FALSE;
> +      if (Data->RedfishServiceIpPort == 443) {
> +        IsHttps = TRUE;
> +      }
> +      StrSize = sizeof(UuidStr);
> +      AsciiSPrint(UuidStr, StrSize, "%g", &Data->ServiceUuid);
> +      //
> +      // Generate Redfish service location string.
> +      //
> +      if (Data->RedfishServiceIpAddressFormat ==
> REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP6) {
> +        NetLibIp6ToStr((IPv6_ADDRESS *)&Data->RedfishServiceIpAddress,
> Ipv6Str, sizeof (Ipv6Str));
> +        if (Data->RedfishServiceIpPort == 0 || IsHttps == TRUE) {
> +            AsciiSPrintUnicodeFormat (
> +              RedfishServiceLocateStr,
> +              sizeof (RedfishServiceLocateStr),
> +              L"%s",
> +              Ipv6Str
> +            );
> +        } else {
> +            AsciiSPrintUnicodeFormat(
> +              RedfishServiceLocateStr,
> +              sizeof (RedfishServiceLocateStr),
> +              L"[%s]:%d",
> +              Ipv6Str,
> +              Data->RedfishServiceIpPort
> +            );
> +        }
> +      } else {
> +        if (Data->RedfishServiceIpPort == 0 || IsHttps == TRUE) {
> +          AsciiSPrint(
> +            RedfishServiceLocateStr,
> +            sizeof (RedfishServiceLocateStr),
> +            "%d.%d.%d.%d",
> +            Data->RedfishServiceIpAddress [0],
> +            Data->RedfishServiceIpAddress [1],
> +            Data->RedfishServiceIpAddress [2],
> +            Data->RedfishServiceIpAddress [3]
> +            );
> +        } else {
> +          AsciiSPrint(
> +            RedfishServiceLocateStr,
> +            sizeof (RedfishServiceLocateStr),
> +            "%d.%d.%d.%d:%d",
> +            Data->RedfishServiceIpAddress [0],
> +            Data->RedfishServiceIpAddress [1],
> +            Data->RedfishServiceIpAddress [2],
> +            Data->RedfishServiceIpAddress [3],
> +            Data->RedfishServiceIpPort
> +            );
> +        }
> +       }
> +      Status = AddAndSignalNewRedfishService (
> +            Instance,
> +            NULL,
> +            RedfishServiceLocateStr,
> +            UuidStr,
> +            NULL,
> +            NULL,
> +            NULL,
> +            NULL,
> +            IsHttps
> +            );
> +    }
> +  }
> +  return Status;
> +}
> +
> +/**
> +  The function adds a new found Redfish service to internal list and
> +  notify client.
> +
> +  @param[in]  Instance
> EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
> +  @param[in]  RedfishVersion        Redfish version.
> +  @param[in]  RedfishLocation       Redfish location.
> +  @param[in]  Uuid                  Service UUID string.
> +  @param[in]  Os                    OS string.
> +  @param[in]  OsVer                 OS version string.
> +  @param[in]  Product               Product string.
> +  @param[in]  ProductVer            Product verison string.
> +  @param[in]  UseHttps              Redfish service requires secured
> connection.
> +  @retval EFI_SUCCESS               Redfish service is added to list
> successfully.
> +
> +**/
> +EFI_STATUS
> +AddAndSignalNewRedfishService (
> +  IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
> +  IN UINTN *RedfishVersion OPTIONAL,
> +  IN CHAR8 *RedfishLocation OPTIONAL,
> +  IN CHAR8 *Uuid  OPTIONAL,
> +  IN CHAR8 *Os  OPTIONAL,
> +  IN CHAR8 *OsVer  OPTIONAL,
> +  IN CHAR8 *Product  OPTIONAL,
> +  IN CHAR8 *ProductVer  OPTIONAL,
> +  IN BOOLEAN UseHttps
> +  )
> +{
> +  BOOLEAN NewFound;
> +  BOOLEAN InfoRefresh;
> +  BOOLEAN RestExOpened;
> +  BOOLEAN DeleteRestEx;
> +  EFI_STATUS Status;
> +  EFI_REDFISH_DISCOVERED_INTERNAL_LIST *DiscoveredList;
> +  EFI_REDFISH_DISCOVERED_INSTANCE *DiscoveredInstance;
> +  CHAR16 *Char16Uuid;
> +  EFI_REST_EX_PROTOCOL *RestEx;
> +  EFI_REST_EX_HTTP_CONFIG_DATA *RestExHttpConfigData;
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *NetworkInterface;
> +
> +  NewFound = TRUE;
> +  InfoRefresh = FALSE;
> +  Char16Uuid = NULL;
> +  RestExOpened = FALSE;
> +  DeleteRestEx = FALSE;
> +
> +  DEBUG ((DEBUG_INFO,"%a:Add this instance to Redfish instance list.\n",
> __FUNCTION__));
> +
> +  if (Uuid != NULL) {
> +    Char16Uuid = (CHAR16 *)AllocateZeroPool(AsciiStrSize((const CHAR8
> *)Uuid) * sizeof(CHAR16));
> +    AsciiStrToUnicodeStrS ((const CHAR8 *)Uuid, Char16Uuid,
> AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
> +  }
> +  DiscoveredList = NULL;
> +  DiscoveredInstance = NULL;
> +  RestExHttpConfigData = NULL;
> +
> +  NetworkInterface = Instance->NetworkInterface;
> +  if (!IsListEmpty (&mRedfishInstanceList)) {
> +    //
> +    // Is this a duplicate redfish service.
> +    //
> +    DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST
> *)GetFirstNode (&mRedfishInstanceList);
> +    NewFound = FALSE;
> +    do {
> +      if (Char16Uuid == NULL ||
> DiscoveredList->Instance->Information.Uuid == NULL) {
> +        //
> +        // Check if this Redfish instance already found using IP
addrress.
> +        //
> +        if (!CheckIsIpVersion6(NetworkInterface)) {
> +          if (CompareMem ((VOID *)&Instance->TargetIpAddress.v4,
> +                      (VOID
> *)&DiscoveredList->Instance->Information.RedfishHostIpAddress.v4,
> +                      sizeof (EFI_IPv4_ADDRESS)
> +                      ) == 0)
> +          {
> +            DiscoveredInstance = DiscoveredList->Instance;
> +            if (DiscoveredList->Instance->Information.Uuid == NULL &&
> +                Char16Uuid != NULL) {
> +              InfoRefresh = TRUE;
> +              DiscoveredInstance = DiscoveredList->Instance;
> +              DEBUG((DEBUG_INFO,"*** This Redfish Service
> information refresh ***\n"));
> +            }
> +            break;
> +          }
> +        } else {
> +          if (CompareMem ((VOID *)&Instance->TargetIpAddress.v6,
> +                      (VOID
> *)&DiscoveredList->Instance->Information.RedfishHostIpAddress.v6,
> +                      sizeof (EFI_IPv6_ADDRESS)
> +                      ) == 0)
> +          {
> +            DiscoveredInstance = DiscoveredList->Instance;
> +            break;
> +          }
> +        }
> +      } else {
> +        //
> +        // Check if this Redfish instance already found using UUID.
> +        //
> +        if (StrCmp((const CHAR16 *)Char16Uuid, (const CHAR16
> *)DiscoveredList->Instance->Information.Uuid) == 0) {
> +          DiscoveredInstance = DiscoveredList->Instance;
> +          break;
> +        }
> +      }
> +      if (IsNodeAtEnd (&mRedfishInstanceList,
> &DiscoveredList->NextInstance)) {
> +        NewFound = TRUE;
> +        break;
> +      }
> +      DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST
> *)GetNextNode (&mRedfishInstanceList, &DiscoveredList->NextInstance);
> +    } while (TRUE);
> +  }
> +  if (NewFound || InfoRefresh) {
> +    if (!InfoRefresh) {
> +      DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST
> *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INTERNAL_LIST));
> +      if (DiscoveredList == NULL) {
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +      InitializeListHead (&DiscoveredList->NextInstance);
> +      DiscoveredInstance = (EFI_REDFISH_DISCOVERED_INSTANCE
> *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INSTANCE));
> +      if (DiscoveredInstance == NULL) {
> +        FreePool ((VOID *)DiscoveredList);
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +    }
> +    DEBUG ((DEBUG_INFO,"*** Redfish Service Information ***\n"));
> +
> +    DiscoveredInstance->Information.UseHttps = UseHttps;
> +    if (RedfishVersion != NULL) {
> +      DiscoveredInstance->Information.RedfishVersion = *RedfishVersion;
> +      DEBUG ((DEBUG_INFO,"Redfish service version: %d.\n",
> DiscoveredInstance->Information.RedfishVersion));
> +    }
> +    if (RedfishLocation != NULL) {
> +      DiscoveredInstance->Information.Location = (CHAR16
> *)AllocatePool(AsciiStrSize((const CHAR8 *)RedfishLocation) *
> sizeof(CHAR16));
> +      AsciiStrToUnicodeStrS ((const CHAR8 *)RedfishLocation,
> DiscoveredInstance->Information.Location, AsciiStrSize((const CHAR8
> *)RedfishLocation) * sizeof(CHAR16));
> +      DEBUG ((DEBUG_INFO,"Redfish service location: %s.\n",
> DiscoveredInstance->Information.Location));
> +    }
> +    if (Uuid != NULL) {
> +      DiscoveredInstance->Information.Uuid = (CHAR16
> *)AllocatePool(AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
> +      AsciiStrToUnicodeStrS ((const CHAR8 *)Uuid,
> DiscoveredInstance->Information.Uuid, AsciiStrSize((const CHAR8 *)Uuid) *
> sizeof(CHAR16));
> +      DEBUG ((DEBUG_INFO,"Service UUID: %s.\n",
> DiscoveredInstance->Information.Uuid));
> +    }
> +    if (Os != NULL) {
> +      DiscoveredInstance->Information.Os = (CHAR16
> *)AllocatePool(AsciiStrSize((const CHAR8 *)Os) * sizeof(CHAR16));
> +      AsciiStrToUnicodeStrS ((const CHAR8 *)Os,
> DiscoveredInstance->Information.Os, AsciiStrSize((const CHAR8 *)Os) *
> sizeof(CHAR16));
> +      DEBUG ((DEBUG_INFO,"Redfish service OS: %s, Version:%s.\n",
> DiscoveredInstance->Information.Os,
> DiscoveredInstance->Information.OsVersion));
> +    }
> +    if (OsVer != NULL) {
> +      DiscoveredInstance->Information.OsVersion = (CHAR16
> *)AllocatePool(AsciiStrSize((const CHAR8 *)OsVer) * sizeof(CHAR16));
> +      AsciiStrToUnicodeStrS ((const CHAR8 *)OsVer,
> DiscoveredInstance->Information.OsVersion, AsciiStrSize((const CHAR8
> *)OsVer) * sizeof(CHAR16));
> +    }
> +    if (Product != NULL && ProductVer != NULL) {
> +      DiscoveredInstance->Information.Product = (CHAR16
> *)AllocatePool(AsciiStrSize((const CHAR8 *)Product) * sizeof(CHAR16));
> +      AsciiStrToUnicodeStrS ((const CHAR8 *)Product,
> DiscoveredInstance->Information.Product, AsciiStrSize((const CHAR8
> *)Product) * sizeof(CHAR16));
> +      DiscoveredInstance->Information.ProductVer = (CHAR16
> *)AllocatePool(AsciiStrSize((const CHAR8 *)ProductVer) * sizeof(CHAR16));
> +      AsciiStrToUnicodeStrS ((const CHAR8 *)ProductVer,
> DiscoveredInstance->Information.ProductVer, AsciiStrSize((const CHAR8
> *)ProductVer) * sizeof(CHAR16));
> +      DEBUG ((DEBUG_INFO,"Redfish service product: %s, Version:%s.\n",
> DiscoveredInstance->Information.Product,
> DiscoveredInstance->Information.ProductVer));
> +    }
> +
> +    if (RedfishLocation == NULL) {
> +      // This is the Redfish reported from SMBIOS 42h
> +      // without validation.
> +
> +      IP4_COPY_ADDRESS((VOID
> *)&DiscoveredInstance->Information.RedfishHostIpAddress.v4, (VOID
> *)&Instance->TargetIpAddress.v4);
> +    }
> +    if (!InfoRefresh) {
> +      DiscoveredList->Instance = DiscoveredInstance;
> +      InsertTailList(&mRedfishInstanceList,
> &DiscoveredList->NextInstance);
> +    }
> +    DiscoveredInstance->Status = EFI_SUCCESS;
> +  } else {
> +    if (DiscoveredList != NULL) {
> +      DEBUG((DEBUG_INFO,"*** This Redfish Service was already found
> ***\n"));
> +      if (DiscoveredInstance->Information.Uuid != NULL) {
> +        DEBUG((DEBUG_INFO,"Service UUID: %s.\n",
> DiscoveredInstance->Information.Uuid));
> +      } else {
> +        DEBUG((DEBUG_INFO,"Service UUID: unknown.\n"));
> +      }
> +    }
> +  }
> +  if (Char16Uuid != NULL) {
> +    FreePool((VOID *)Char16Uuid);
> +  }
> +
> +  Status = EFI_SUCCESS;
> +  if (NewFound || InfoRefresh) {
> +    //
> +    // Build up EFI_REDFISH_DISCOVERED_LIST in token.
> +    //
> +    Instance->DiscoverToken->DiscoverList.NumberOfServiceFound = 1;
> +    Instance->DiscoverToken->DiscoverList.RedfishInstances =
> DiscoveredInstance;
> +    DiscoveredInstance->Status = EFI_SUCCESS;
> +    if (!InfoRefresh) {
> +      Status = CreateRestExInstance (Instance, Instance->DiscoverToken);
> // Create REST EX child.
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "%a:Can't create REST EX child
> instance.\n",__FUNCTION__));
> +        goto ON_EXIT;
> +      }
> +      Status = gBS->OpenProtocol ( // Configure local host information.
> +
> Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.Redfis
> hRestExHandle,
> +                  &gEfiRestExProtocolGuid,
> +                  (VOID **)&RestEx,
> +
> Instance->NetworkInterface->OpenDriverAgentHandle,
> +
> Instance->NetworkInterface->OpenDriverControllerHandle,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
> +      if (EFI_ERROR (Status)) {
> +        DeleteRestEx = TRUE;
> +        goto ERROR_EXIT;
> +      }
> +      RestExOpened = TRUE;
> +      RestExHttpConfigData = AllocateZeroPool (sizeof
> (EFI_REST_EX_HTTP_CONFIG_DATA));
> +      if (RestExHttpConfigData == NULL) {
> +        Status = EFI_OUT_OF_RESOURCES;
> +        DeleteRestEx = TRUE;
> +        goto EXIT_FREE_CONFIG_DATA;
> +      }
> +      RestExHttpConfigData->SendReceiveTimeout = 5000;
> +      RestExHttpConfigData->HttpConfigData.HttpVersion =
> HttpVersion11;
> +      RestExHttpConfigData->HttpConfigData.LocalAddressIsIPv6 =
> CheckIsIpVersion6(NetworkInterface);
> +      if (RestExHttpConfigData->HttpConfigData.LocalAddressIsIPv6) {
> +        RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node =
> AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT));
> +        if (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node
> == NULL) {
> +          Status = EFI_OUT_OF_RESOURCES;
> +          goto EXIT_FREE_CONFIG_DATA;
> +        }
> +      } else {
> +        RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node =
> AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT));
> +        if (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node
> == NULL) {
> +          Status = EFI_OUT_OF_RESOURCES;
> +          goto EXIT_FREE_CONFIG_DATA;
> +        }
> +
> RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node->UseDefaultA
> ddress = TRUE;
> +      }
> +      Status = RestEx->Configure (
> +                       RestEx,
> +                       (EFI_REST_EX_CONFIG_DATA)(UINT8
> *)RestExHttpConfigData
> +                       );
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR,"%a:REST EX configured..\n",
> __FUNCTION__));
> +        DeleteRestEx = TRUE;
> +        goto EXIT_FREE_ALL;
> +      }
> +      //
> +      // Signal client, close REST EX before signaling client.
> +      //
> +      if (RestExOpened) {
> +        gBS->CloseProtocol(
> +
> Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.Redfis
> hRestExHandle,
> +             &gEfiRestExProtocolGuid,
> +             Instance->NetworkInterface->OpenDriverAgentHandle,
> +             Instance->NetworkInterface->OpenDriverControllerHandle
> +          );
> +        RestExOpened = FALSE;
> +      }
> +    }
> +    Status = gBS->SignalEvent(Instance->DiscoverToken->Event);
> +    if (!EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR,"%a:No event to signal!\n",
> __FUNCTION__));
> +    }
> +  }
> +
> +EXIT_FREE_ALL:;
> +  if (RestExHttpConfigData != NULL &&
> RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node != NULL) {
> +    FreePool
> (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node);
> +  }
> +
> +EXIT_FREE_CONFIG_DATA:;
> +  if (RestExHttpConfigData != NULL) {
> +    FreePool((VOID *)RestExHttpConfigData);
> +  }
> +  if (RestExOpened) {
> +    gBS->CloseProtocol(
> +
> Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.Redfis
> hRestExHandle,
> +           &gEfiRestExProtocolGuid,
> +           Instance->NetworkInterface->OpenDriverAgentHandle,
> +           Instance->NetworkInterface->OpenDriverControllerHandle
> +        );
> +  }
> +ERROR_EXIT:;
> +    if (DeleteRestEx && RestExOpened) {
> +      gBS->CloseProtocol(
> +
> Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.Redfis
> hRestExHandle,
> +           &gEfiRestExProtocolGuid,
> +           Instance->NetworkInterface->OpenDriverAgentHandle,
> +           Instance->NetworkInterface->OpenDriverControllerHandle
> +        );
> +    }
> +ON_EXIT:;
> +  return Status;
> +}
> +
> +/**
> +  This function gets the subnet information of this network interface
> instance.
> +  can discover Redfish service on it.
> +
> +  @param[in]    Instance
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance.
> +  @param[in]    ImageHandle  EFI Image handle request the network
> interface list.
> +
> +  @retval EFI_SUCCESS
> +
> +**/
> +EFI_STATUS
> +NetworkInterfaceGetSubnetInfo (
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *Instance,
> +  IN EFI_HANDLE ImageHandle
> +  )
> +{
> +  EFI_STATUS Status;
> +  UINT32 ProtocolType;
> +  UINT32 IPv6InfoIndex;
> +  EFI_IP6_ADDRESS_INFO *ThisSubnetAddrInfoIPv6;
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *NewNetworkInterface;
> +
> +  if (Instance->GotSubnetInfo) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  ProtocolType = Instance->NetworkProtocolType;
> +  if (gRequiredProtocol [ProtocolType].GetSubnetInfo != NULL &&
> Instance->GotSubnetInfo == FALSE) {
> +    Status = gRequiredProtocol [ProtocolType].GetSubnetInfo (
> +        ImageHandle,
> +        Instance
> +        );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR,"%a:Faile to get Subnet infomation.\n",
> __FUNCTION__));
> +      return Status;
> +    } else {
> +      DEBUG ((DEBUG_INFO,"%a:MAC address: %s\n", __FUNCTION__,
> Instance->StrMacAddr));
> +      if (CheckIsIpVersion6 (Instance)) {
> +        if (Instance->SubnetAddrInfoIPv6Number == 0) {
> +          DEBUG ((DEBUG_ERROR,"%a: There is no Subnet infomation for
> IPv6 network interface.\n", __FUNCTION__));
> +          return EFI_NOT_FOUND;
> +        }
> +        ThisSubnetAddrInfoIPv6 = Instance->SubnetAddrInfoIPv6; // First
> IPv6 address information.
> +        IP6_COPY_ADDRESS (&Instance->SubnetAddr.v6,
> &ThisSubnetAddrInfoIPv6->Address);
> +        Instance->SubnetPrefixLength =
> ThisSubnetAddrInfoIPv6->PrefixLength;
> +        DEBUG((DEBUG_INFO,"   IPv6 Subnet ID:%d, Prefix
> length: %d.\n",
> +               ThisSubnetAddrInfoIPv6->Address.Addr [7] +
> (UINT16)ThisSubnetAddrInfoIPv6->Address.Addr [6] * 256,
> +               ThisSubnetAddrInfoIPv6->PrefixLength)
> +               );
> +        //
> +        // If this is IPv6, then we may have to propagate network
interface
> for IPv6 network scopes
> +        // according to the Ipv6 address information.
> +        //
> +        ThisSubnetAddrInfoIPv6 ++;
> +        for (IPv6InfoIndex = 0; IPv6InfoIndex <
> Instance->SubnetAddrInfoIPv6Number - 1; IPv6InfoIndex++) {
> +          //
> +          // Build up addtional
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instances.
> +          //
> +          NewNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)AllocateZeroPool (sizeof
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL));
> +          if (NewNetworkInterface != NULL) {
> +            CopyMem ((VOID *)NewNetworkInterface, (VOID *)Instance,
> sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL)); //
> Clone information of first instance.
> +            IP6_COPY_ADDRESS
> (&NewNetworkInterface->SubnetAddr.v6,
> &ThisSubnetAddrInfoIPv6->Address);
> +            NewNetworkInterface->SubnetPrefixLength =
> ThisSubnetAddrInfoIPv6->PrefixLength;
> +            NewNetworkInterface->GotSubnetInfo = TRUE;
> +            InsertTailList (&mEfiRedfishDiscoverNetworkInterface,
> &NewNetworkInterface->Entry);
> +            ThisSubnetAddrInfoIPv6 ++;
> +            mNumNetworkInterface ++;
> +            DEBUG((DEBUG_INFO,"   IPv6 Subnet ID:%d, Prefix
> length: %d.\n",
> +                   ThisSubnetAddrInfoIPv6->Address.Addr [7] +
> (UINT16)ThisSubnetAddrInfoIPv6->Address.Addr [6] * 256,
> +                   ThisSubnetAddrInfoIPv6->PrefixLength)
> +                  );
> +          } else {
> +            return EFI_OUT_OF_RESOURCES;
> +          }
> +        }
> +      } else {
> +        DEBUG ((DEBUG_INFO,"   IPv4 Subnet:%d.%d.%d.%d Subnet
> mask: %d.%d.%d.%d.\n",
> +                    Instance->SubnetAddr.v4.Addr [0],
> +                    Instance->SubnetAddr.v4.Addr [1],
> +                    Instance->SubnetAddr.v4.Addr [2],
> +                    Instance->SubnetAddr.v4.Addr [3],
> +                    Instance->SubnetMask.v4.Addr [0],
> +                    Instance->SubnetMask.v4.Addr [1],
> +                    Instance->SubnetMask.v4.Addr [2],
> +                    Instance->SubnetMask.v4.Addr [3]
> +                    ));
> +      }
> +    }
> +  }
> +  Instance->GotSubnetInfo = TRUE; // Only try to get Subnet Info once.
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function gets the network interface list which Redfish discover
> protocol
> +  can discover Redfish service on it.
> +
> +  @param[in]    This
> EFI_REDFISH_DISCOVER_PROTOCOL instance.
> +  @param[in]    ImageHandle           EFI Image handle request the
> network interface list,
> +  @param[out]   NumberOfNetworkIntfs  Number of network interfaces
> can do Redfish service discovery.
> +  @param[out]   NetworkIntfInstances  Network interface instances.
> It's an array of instance. The number of entries
> +                                      in array is indicated by
> NumberOfNetworkIntfs.
> +                                      Caller has to release the
> memory
> +                                      allocated by Redfish discover
> protocol.
> +
> +  @retval EFI_SUCCESS        The information of network interface is
> returned in NumberOfNetworkIntfs and
> +                             NetworkIntfInstances.
> +  @retval Others             Fail to return the information of network
> interface.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishServiceGetNetworkInterface (
> +  IN EFI_REDFISH_DISCOVER_PROTOCOL   *This,
> +  IN EFI_HANDLE                      ImageHandle,
> +  OUT UINTN                          *NumberOfNetworkIntfs,
> +  OUT EFI_REDFISH_DISCOVER_NETWORK_INTERFACE
> **NetworkIntfInstances
> +)
> +{
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *ThisNetworkInterfaceIntn;
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *ThisNetworkInterface;
> +
> +  if (NetworkIntfInstances == NULL || NumberOfNetworkIntfs == NULL ||
> ImageHandle == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *NumberOfNetworkIntfs = 0;
> +  *NetworkIntfInstances = NULL;
> +
> +  if (IsListEmpty ((const
> LIST_ENTRY*)&mEfiRedfishDiscoverNetworkInterface)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE
> *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE)
> * mNumNetworkInterface);
> +  if (ThisNetworkInterface == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +  *NetworkIntfInstances = ThisNetworkInterface;
> +  ThisNetworkInterfaceIntn =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode
> (&mEfiRedfishDiscoverNetworkInterface);
> +  while (TRUE) {
> +    ThisNetworkInterface->IsIpv6 = FALSE;
> +    if (CheckIsIpVersion6 (ThisNetworkInterfaceIntn)) {
> +      ThisNetworkInterface->IsIpv6 = TRUE;
> +    }
> +    CopyMem((VOID *)&ThisNetworkInterface->MacAddress,
> &ThisNetworkInterfaceIntn->MacAddress,
> ThisNetworkInterfaceIntn->HwAddressSize);
> +    NetworkInterfaceGetSubnetInfo(ThisNetworkInterfaceIntn,
> ImageHandle); // Get subnet info.
> +    if (!ThisNetworkInterface->IsIpv6) {
> +      IP4_COPY_ADDRESS(&ThisNetworkInterface->SubnetId.v4,
> &ThisNetworkInterfaceIntn->SubnetAddr.v4); // IPv4 subnet information.
> +    } else {
> +      IP6_COPY_ADDRESS (&ThisNetworkInterface->SubnetId.v6,
> &ThisNetworkInterfaceIntn->SubnetAddr.v6); // IPv6 subnet information in
> IPv6 address information.
> +    }
> +    ThisNetworkInterface->SubnetPrefixLength =
> ThisNetworkInterfaceIntn->SubnetPrefixLength;
> +    ThisNetworkInterface->VlanId = ThisNetworkInterfaceIntn->VlanId;
> +    (*NumberOfNetworkIntfs) ++;
> +    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface,
> &ThisNetworkInterfaceIntn->Entry)) {
> +      break;
> +    }
> +    ThisNetworkInterfaceIntn =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> &ThisNetworkInterfaceIntn->Entry);
> +    ThisNetworkInterface ++;
> +  };
> +  return EFI_SUCCESS;
> +}
> +/**
> +  This function acquires Redfish services by discovering static Redfish
setting
> +  according to Redfish Host Interface or through SSDP. Returns a list of
EFI
> +  handles in EFI_REDFISH_DISCOVERED_LIST. Each of EFI handle has
> cooresponding
> +  EFI REST EX instance installed on it. Each REST EX isntance is a child
> instance which
> +  created through EFI REST EX serivce protoocl for communicating with
> specific
> +  Redfish service.
> +
> +  @param[in]    This
> EFI_REDFISH_DISCOVER_PROTOCOL instance.
> +  @param[in]    ImageHandle             EFI image owns these
> Redfish service instances.
> +  @param[in]    TargetNetworkInterface  Target network interface to
> do the discovery.
> +                                        NULL means discover
> Redfish service on all network interfaces on platform.
> +  @param[in]    Flags                   Redfish service discover
> flags.
> +  @param[in]    Token
> EFI_REDFISH_DISCOVERED_TOKEN instance.
> +                                        The memory of
> EFI_REDFISH_DISCOVERED_LIST and the strings in
> +
> EFI_REDFISH_DISCOVERED_INFORMATION are all allocated by Acquire()
> +                                        and must be freed when
> caller invoke Release().
> +
> +  @retval EFI_SUCCESS             REST EX instance of discovered
> Redfish services are returned.
> +  @retval EFI_INVALID_PARAMETERS  ImageHandle == NULL, Flags == 0,
> Token == NULL, Token->Timeout > 5,
> +                                  or Token->Event == NULL.
> +  @retval Others                  Fail acquire Redfish services.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishServiceAcquireService (
> +  IN EFI_REDFISH_DISCOVER_PROTOCOL          *This,
> +  IN EFI_HANDLE                             ImageHandle,
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE
> *TargetNetworkInterface,
> +  IN EFI_REDFISH_DISCOVER_FLAG              Flags,
> +  IN EFI_REDFISH_DISCOVERED_TOKEN           *Token
> +  )
> +{
> +  EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance;
> +  EFI_STATUS Status1;
> +  EFI_STATUS Status2;
> +  BOOLEAN NewInstance;
> +  UINTN NumNetworkInterfaces;
> +  UINTN NetworkInterfacesIndex;
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *TargetNetworkInterfaceInternal;
> +
> +  DEBUG ((DEBUG_INFO,"%a:Entry.\n", __FUNCTION__));
> +
> +  //
> +  // Validate parameters.
> +  //
> +  if (ImageHandle == NULL || Token == NULL || ((Flags &
> ~EFI_REDFISH_DISCOVER_VALIDATION) == 0)) {
> +    DEBUG ((DEBUG_ERROR,"%a:Invalid parameters.\n",
> __FUNCTION__));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  //
> +  // Validate target network interface.
> +  //
> +  if (EFI_ERROR (ValidateTargetNetworkInterface (TargetNetworkInterface,
> Flags))) {
> +      return EFI_UNSUPPORTED;
> +  }
> +  if (TargetNetworkInterface != NULL) {
> +    TargetNetworkInterfaceInternal = GetTargetNetworkInterfaceInternal
> (TargetNetworkInterface);
> +    NumNetworkInterfaces = 1;
> +  } else {
> +    TargetNetworkInterfaceInternal =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode
> (&mEfiRedfishDiscoverNetworkInterface);
> +    NumNetworkInterfaces = NumberOfNetworkInterface ();
> +    if (NumNetworkInterfaces == 0) {
> +      DEBUG ((DEBUG_ERROR,"%a:No network interface on platform.\n",
> __FUNCTION__));
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +  for (NetworkInterfacesIndex = 0; NetworkInterfacesIndex <
> NumNetworkInterfaces; NetworkInterfacesIndex ++) {
> +    Status1 = EFI_SUCCESS;
> +    Status2 = EFI_SUCCESS;
> +    NewInstance = FALSE;
> +    Instance = GetInstanceByOwner (ImageHandle,
> TargetNetworkInterfaceInternal, Flags &
> ~EFI_REDFISH_DISCOVER_VALIDATION); // Check if we can re-use previous
> instance.
> +    if (Instance == NULL) {
> +      DEBUG ((DEBUG_INFO,"%a:Create new
> EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.\n", __FUNCTION__));
> +      Instance = (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
> *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE))
> ;
> +      if (Instance == NULL) {
> +        DEBUG ((DEBUG_ERROR,"%a:Memory allocation fail.\n",
> __FUNCTION__));
> +      }
> +      InitializeListHead (&Instance->Entry);
> +      Instance->Owner = ImageHandle;
> +      Instance->DiscoverFlags = Flags &
> ~EFI_REDFISH_DISCOVER_VALIDATION;
> +      Instance->NetworkInterface = TargetNetworkInterfaceInternal;
> +      //
> +      // Get subnet information in case subnet information is not set
> because
> +      // RedfishServiceGetNetworkInterfaces hasn't been called yet.
> +      //
> +      NetworkInterfaceGetSubnetInfo (TargetNetworkInterfaceInternal,
> ImageHandle);
> +      NewInstance = TRUE;
> +    }
> +    if (TargetNetworkInterfaceInternal->StrMacAddr != NULL) {
> +      DEBUG((DEBUG_INFO,"%a:Acquire Redfish service on network
> interface MAC address:%s.\n", __FUNCTION__,
> TargetNetworkInterfaceInternal->StrMacAddr));
> +    } else {
> +      DEBUG((DEBUG_INFO,"%a:WARNING: No MAC address on this
> network interface.\n", __FUNCTION__));
> +    }
> +
> +    Instance->DiscoverToken = Token; // Always use the latest Token
> passed by caller.
> +    if ((Flags & EFI_REDFISH_DISCOVER_HOST_INTERFACE) != 0) {
> +      DEBUG ((DEBUG_INFO,"%a:Redfish HOST interface discovery.\n",
> __FUNCTION__));
> +      Instance->HostIntfValidation = FALSE;
> +      if ((Flags & EFI_REDFISH_DISCOVER_VALIDATION) != 0) {
> +        Instance->HostIntfValidation = TRUE;
> +      }
> +      Status1 = DiscoverRedfishHostInterface (Instance); // Discover
> Redfish service through Redfish Host Interface.
> +    }
> +    if ((Flags & EFI_REDFISH_DISCOVER_SSDP) != 0) {
> +      DEBUG ((DEBUG_ERROR,"%a:Redfish service discovery through SSDP
> is not supported\n", __FUNCTION__));
> +      return EFI_UNSUPPORTED;
> +    } else {
> +      if (EFI_ERROR (Status1) && EFI_ERROR (Status2)) {
> +        FreePool ((VOID *)Instance);
> +        DEBUG ((DEBUG_ERROR,"%a:Something wrong on Redfish service
> discovery Status1=%x, Status2=%x.\n", __FUNCTION__, Status1, Status2));
> +      } else {
> +        if (NewInstance) {
> +          InsertTailList(&mRedfishDiscoverList, &Instance->Entry);
> +        }
> +      }
> +    }
> +    if (TargetNetworkInterface == NULL) {
> +      //
> +      // Discover Redfish services on all of network interfaces.
> +      //
> +      TargetNetworkInterfaceInternal =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> &TargetNetworkInterfaceInternal->Entry);
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function aborts Redfish service discovery on the given network
> interface.
> +
> +  @param[in]    This
> EFI_REDFISH_DISCOVER_PROTOCOL instance.
> +  @param[in]    TargetNetworkInterface  Target network interface to
> do the discovery.
> +
> +  @retval EFI_SUCCESS             REST EX instance of discovered
> Redfish services are returned.
> +  @retval Others                  Fail to abort Redfish service
> discovery.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishServiceAbortAcquire (
> +  IN EFI_REDFISH_DISCOVER_PROTOCOL      *This,
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE
> *TargetNetworkInterface OPTIONAL
> +)
> +{
> +  // This function is used to abort Redfish service discovery through
SSDP
> +  // on the network interface. SSDP is optionally supprted by
> EFI_REDFISH_DISCOVER_PROTOCOL,
> +  // we dont have implementation for SSDP now.
> +
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +  This function releases Redfish services found by
RedfishServiceAcquire().
> +
> +  @param[in]    This         EFI_REDFISH_DISCOVER_PROTOCOL
> instance.
> +  @param[in]    InstanceList The Redfish service to release.
> +
> +  @retval EFI_SUCCESS        REST EX instances of discovered Redfish
> are released.
> +  @retval Others             Fail to remove the entry
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishServiceReleaseService (
> +  IN EFI_REDFISH_DISCOVER_PROTOCOL   *This,
> +  IN EFI_REDFISH_DISCOVERED_LIST *InstanceList
> +  )
> +{
> +  UINTN NumService;
> +  BOOLEAN AnyFailRelease;
> +  EFI_REDFISH_DISCOVERED_INSTANCE *ThisRedfishInstance;
> +  EFI_REDFISH_DISCOVERED_INTERNAL_LIST *DiscoveredRedfishInstance;
> +
> +  if (IsListEmpty (&mRedfishInstanceList)) {
> +    DEBUG ((DEBUG_ERROR,"%a:No any discovered Redfish service.\n",
> __FUNCTION__));
> +    return EFI_NOT_FOUND;
> +  }
> +  AnyFailRelease = FALSE;
> +  ThisRedfishInstance = InstanceList->RedfishInstances;
> +  for (NumService = 0; NumService < InstanceList->NumberOfServiceFound;
> NumService ++) {
> +    DiscoveredRedfishInstance =
> (EFI_REDFISH_DISCOVERED_INTERNAL_LIST
> *)GetFirstNode(&mRedfishInstanceList);
> +    do {
> +      if (DiscoveredRedfishInstance->Instance == ThisRedfishInstance) {
> +        RemoveEntryList (&DiscoveredRedfishInstance->NextInstance);
> +        if (ThisRedfishInstance->Information.Location != NULL) {
> +          FreePool (ThisRedfishInstance->Information.Location);
> +        }
> +        if (ThisRedfishInstance->Information.Uuid != NULL) {
> +          FreePool (ThisRedfishInstance->Information.Uuid);
> +        }
> +        if (ThisRedfishInstance->Information.Os != NULL) {
> +          FreePool (ThisRedfishInstance->Information.Os);
> +        }
> +        if (ThisRedfishInstance->Information.OsVersion != NULL) {
> +          FreePool (ThisRedfishInstance->Information.OsVersion);
> +        }
> +        if (ThisRedfishInstance->Information.Product != NULL) {
> +          FreePool (ThisRedfishInstance->Information.Product);
> +        }
> +        if (ThisRedfishInstance->Information.ProductVer != NULL) {
> +          FreePool (ThisRedfishInstance->Information.ProductVer);
> +        }
> +        FreePool((VOID *)ThisRedfishInstance);
> +        goto ReleaseNext;
> +      }
> +
> +      if (IsNodeAtEnd(&mRedfishInstanceList,
> &DiscoveredRedfishInstance->NextInstance)) {
> +        break;
> +      }
> +      DiscoveredRedfishInstance =
> (EFI_REDFISH_DISCOVERED_INTERNAL_LIST
> *)GetNextNode(&mRedfishInstanceList,
> &DiscoveredRedfishInstance->NextInstance);
> +    } while (TRUE);
> +    AnyFailRelease = TRUE;
> +ReleaseNext:;
> +    //
> +    // Release next discovered Redfish Service.
> +    //
> +    ThisRedfishInstance = (EFI_REDFISH_DISCOVERED_INSTANCE
> *)((UINT8 *)ThisRedfishInstance + sizeof
> (EFI_REDFISH_DISCOVERED_INSTANCE));
> +  }
> +  if (AnyFailRelease) {
> +    return EFI_NOT_FOUND;
> +  } else {
> +    return EFI_SUCCESS;
> +  }
> +}
> +
> +EFI_REDFISH_DISCOVER_PROTOCOL mRedfishDiscover = {
> +  RedfishServiceGetNetworkInterface,
> +  RedfishServiceAcquireService,
> +  RedfishServiceAbortAcquire,
> +  RedfishServiceReleaseService
> +};
> +
> +/**
> +  This function create an
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL for the
> +  given network interface.
> +
> +
> +  @param[in]  ControllerHandle    MAC address of this network
> interface.
> +  @param[in]  NetworkProtocolType Network protocol type.
> +  @param[out] IsNewInstance       BOOLEAN means new instance or
> not.
> +  @param[out] NetworkInterface    Pointer to to
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL.
> +
> +  @retval EFI_STATUS
> +**/
> +EFI_STATUS
> +CreateRedfishDiscoverNetworkInterface (
> +  IN EFI_HANDLE ControllerHandle,
> +  IN UINT32 NetworkProtocolType,
> +  OUT BOOLEAN  *IsNewInstance,
> +  OUT EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> **NetworkInterface
> +  )
> +{
> +  EFI_MAC_ADDRESS MacAddress;
> +  UINTN HwAddressSize;
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *ThisNetworkInterface;
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *NewNetworkInterface;
> +
> +  NetLibGetMacAddress (ControllerHandle, &MacAddress,
> &HwAddressSize);
> +  NewNetworkInterface = NULL;
> +  *IsNewInstance = TRUE;
> +  if (!IsListEmpty ((const
> LIST_ENTRY*)&mEfiRedfishDiscoverNetworkInterface)) {
> +    //
> +    // Check if this instance already exist.
> +    //
> +    ThisNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode
> (&mEfiRedfishDiscoverNetworkInterface);
> +    if (ThisNetworkInterface != NULL) {
> +      while (TRUE) {
> +        if ((CompareMem ((CONST VOID
> *)&ThisNetworkInterface->MacAddress.Addr, (CONST VOID
> *)&MacAddress.Addr, HwAddressSize) == 0) &&
> +             (ThisNetworkInterface->NetworkProtocolType ==
> NetworkProtocolType)){
> +          NewNetworkInterface = ThisNetworkInterface;
> +          *IsNewInstance = FALSE;
> +          break;
> +        }
> +        if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface,
> &ThisNetworkInterface->Entry)) {
> +          NewNetworkInterface = NULL;
> +          break;
> +        }
> +        ThisNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> &ThisNetworkInterface->Entry);
> +      };
> +    }
> +  }
> +  if (NewNetworkInterface == NULL) {
> +    //
> +    // Create a new instance.
> +    //
> +    NewNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)AllocateZeroPool (sizeof
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL));
> +    if (NewNetworkInterface == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +    NewNetworkInterface->HwAddressSize = HwAddressSize;
> +    CopyMem (&NewNetworkInterface->MacAddress.Addr,
> &MacAddress.Addr, NewNetworkInterface->HwAddressSize);
> +    NetLibGetMacString (ControllerHandle, NULL,
> &NewNetworkInterface->StrMacAddr);
> +    NewNetworkInterface->VlanId = NetLibGetVlanId (ControllerHandle);
> +  }
> +  *NetworkInterface = NewNetworkInterface;
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function destory network interface
> +
> +
> +  @param[in]  ThisNetworkInterface
> EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance.
> +
> +  @retval EFI_STATUS
> +**/
> +EFI_STATUS
> +DestroyRedfishNetwrokInterface (
> +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *ThisNetworkInterface
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status = gBS->UninstallProtocolInterface(
> +                  ThisNetworkInterface->OpenDriverControllerHandle,
> +                  gRequiredProtocol
> [ThisNetworkInterface->NetworkProtocolType].DiscoveredProtocolGuid,
> +
> &ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolDiscoverId
> +                  );
> +  RemoveEntryList (&ThisNetworkInterface->Entry);
> +  mNumNetworkInterface --;
> +  FreePool (ThisNetworkInterface);
> +  return Status;
> +}
> +
> +/**
> +  Tests to see if the required protocols are provided on the given
> +  controller handle.
> +
> +  @param[in]  This                 A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL instance.
> +  @param[in]  ControllerHandle     The handle of the controller to test.
> This handle
> +                                   must support a protocol
> interface that supplies
> +                                   an I/O abstraction to the driver.
> +  @retval EFI_SUCCESS              One of required protocol is found.
> +  @retval EFI_UNSUPPORTED          None of required protocol is
> found.
> +**/
> +EFI_STATUS
> +TestForRequiredProtocols (
> +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> +  IN EFI_HANDLE ControllerHandle
> +  )
> +{
> +  UINT32 Id;
> +  UINTN Index;
> +  EFI_STATUS Status;
> +
> +  for (Index = 0; Index < (sizeof (gRequiredProtocol) / sizeof
> (REDFISH_DISCOVER_REQUIRED_PROTOCOL)); Index ++) {
> +    Status = gBS->OpenProtocol (
> +                  ControllerHandle,
> +                  gRequiredProtocol
> [Index].RequiredServiceBindingProtocolGuid,
> +                  NULL,
> +                  This->DriverBindingHandle,
> +                  ControllerHandle,
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> +                  );
> +    if (!EFI_ERROR (Status)) {
> +      Status = gBS->OpenProtocol (
> +                      ControllerHandle,
> +                      gRequiredProtocol
> [Index].DiscoveredProtocolGuid,
> +                      (VOID **) &Id,
> +                      This->DriverBindingHandle,
> +                      ControllerHandle,
> +                      EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                      );
> +      if (EFI_ERROR (Status)) {
> +        DEBUG((DEBUG_ERROR, "%a: %s is found on this controller
> handle.\n", __FUNCTION__, gRequiredProtocol [Index].ProtocolName));
> +        return EFI_SUCCESS;
> +      }
> +    }
> +  }
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +  Build up network interface and create corresponding service through the
> given
> +  controller handle.
> +
> +  @param[in]  This                 A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL instance.
> +  @param[in]  ControllerHandle     The handle of the controller to test.
> This handle
> +                                   must support a protocol
> interface that supplies
> +                                   an I/O abstraction to the driver.
> +  @retval EFI_SUCCESS              One of required protocol is found.
> +  @retval EFI_UNSUPPORTED          None of required protocol is
> found.
> +  @retval EFI_UNSUPPORTED          Failed to build up network
> interface.
> +**/
> +EFI_STATUS
> +BuildupNetworkInterface (
> +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> +  IN EFI_HANDLE ControllerHandle
> +  )
> +{
> +  UINT32 Id;
> +  UINT32 Index;
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *NetworkInterface;
> +  BOOLEAN IsNew;
> +  EFI_STATUS Status;
> +  VOID *TempInterface;
> +  VOID **Interface;
> +  UINT32 *ProtocolDiscoverIdPtr;
> +  EFI_HANDLE OpenDriverAgentHandle;
> +  EFI_HANDLE OpenDriverControllerHandle;
> +  EFI_HANDLE *HandleOfProtocolInterfacePtr;
> +  EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL
> *RestExInstance;
> +  EFI_TPL OldTpl;
> +  BOOLEAN NewNetworkInterfaceInstalled;
> +
> +  NewNetworkInterfaceInstalled = FALSE;
> +  Index = 0;
> +  do {
> +    Status = gBS->OpenProtocol ( // Already in list?
> +                    ControllerHandle,
> +                    gRequiredProtocol [Index].DiscoveredProtocolGuid,
> +                    (VOID **) &Id,
> +                    This->DriverBindingHandle,
> +                    ControllerHandle,
> +                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                    );
> +    if (!EFI_ERROR (Status)) {
> +      Index ++;
> +      if (Index == (sizeof(gRequiredProtocol) /
> sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
> +        break;
> +      }
> +      continue;
> +    }
> +
> +    Status = gBS->OpenProtocol (
> +                    ControllerHandle,
> +                    gRequiredProtocol
> [Index].RequiredServiceBindingProtocolGuid,
> +                    &TempInterface,
> +                    This->DriverBindingHandle,
> +                    ControllerHandle,
> +                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      Index ++;
> +      if (Index == (sizeof(gRequiredProtocol) /
> sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
> +        break;
> +      }
> +      continue;
> +    }
> +    if (gRequiredProtocol [Index].ProtocolType != ProtocolTypeRestEx) {
> +      OldTpl = gBS->RaiseTPL
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
> +      Status = CreateRedfishDiscoverNetworkInterface(ControllerHandle,
> gRequiredProtocol [Index].ProtocolType, &IsNew, &NetworkInterface);
> +      if (EFI_ERROR (Status)) {
> +        gBS->RestoreTPL (OldTpl);
> +        return Status;
> +      }
> +      NetworkInterface->NetworkProtocolType = gRequiredProtocol
> [Index].ProtocolType;
> +      NetworkInterface->OpenDriverAgentHandle =
> This->DriverBindingHandle;
> +      NetworkInterface->OpenDriverControllerHandle = ControllerHandle;
> +      NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolGuid = \
> +        *gRequiredProtocol [Index].RequiredProtocolGuid;
> +
> NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolServiceGuid = \
> +        *gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid;
> +      ProtocolDiscoverIdPtr =
> &NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolDiscoverId;
> +      OpenDriverAgentHandle =
> NetworkInterface->OpenDriverAgentHandle;
> +      OpenDriverControllerHandle =
> NetworkInterface->OpenDriverControllerHandle;
> +      HandleOfProtocolInterfacePtr =
> &NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle
> ;
> +      Interface =
> &NetworkInterface->NetworkInterfaceProtocolInfo.NetworkProtocolInterfac
> e;
> +      NewNetworkInterfaceInstalled = TRUE;
> +      if (IsNew) {
> +        InsertTailList (&mEfiRedfishDiscoverNetworkInterface,
> &NetworkInterface->Entry);
> +        mNumNetworkInterface ++;
> +      }
> +      gBS->RestoreTPL (OldTpl);
> +    } else {
> +      // Record REST_EX instance. REST_EX is created when clinet asks for
> Redfish service discovery.
> +      // Redfish Service Discover protocol will match REST EX to the
> corresponding EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> +      // when discovery.
> +
> +      RestExInstance =
> (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)AllocateZeroPool
> (sizeof (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL));
> +      if (RestExInstance == NULL) {
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +      RestExInstance->OpenDriverAgentHandle =
> This->DriverBindingHandle;
> +      RestExInstance->OpenDriverControllerHandle = ControllerHandle;
> +      RestExInstance->RestExControllerHandle = ControllerHandle;
> +      InitializeListHead (&RestExInstance->Entry);
> +      InsertTailList (&mEfiRedfishDiscoverRestExInstance,
> &RestExInstance->Entry);
> +      mNumRestExInstance ++;
> +      ProtocolDiscoverIdPtr = &RestExInstance->RestExId;
> +      OpenDriverAgentHandle =
> RestExInstance->OpenDriverAgentHandle;
> +      OpenDriverControllerHandle =
> RestExInstance->OpenDriverControllerHandle;
> +      HandleOfProtocolInterfacePtr =
> &RestExInstance->RestExChildHandle;
> +      Interface = (VOID **)&RestExInstance->RestExProtocolInterface;
> +    }
> +    Status = gBS->InstallProtocolInterface (
> +                    &ControllerHandle,
> +                    gRequiredProtocol [Index].DiscoveredProtocolGuid,
> +                    EFI_NATIVE_INTERFACE,
> +                    ProtocolDiscoverIdPtr
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      Index ++;
> +      if (Index == (sizeof(gRequiredProtocol) /
> sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
> +        break;
> +      }
> +      continue;
> +    }
> +    //
> +    // Create service binding child and open it BY_DRIVER.
> +    //
> +    Status = NetLibCreateServiceChild (
> +              ControllerHandle,
> +              This->ImageHandle,
> +              gRequiredProtocol
> [Index].RequiredServiceBindingProtocolGuid,
> +              HandleOfProtocolInterfacePtr
> +              );
> +    if (!EFI_ERROR (Status)) {
> +      Status = gBS->OpenProtocol (
> +                    *HandleOfProtocolInterfacePtr,
> +                    gRequiredProtocol [Index].RequiredProtocolGuid,
> +                    Interface,
> +                    OpenDriverAgentHandle,
> +                    OpenDriverControllerHandle,
> +                    EFI_OPEN_PROTOCOL_BY_DRIVER
> +                    );
> +      if (!EFI_ERROR (Status)) {
> +        if (EfiRedfishDiscoverProtocolHandle == NULL &&
> +            (gRequiredProtocol [Index].ProtocolType ==
> ProtocolTypeRestEx) &&
> +            !IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)
> +            ) {
> +          // Install the fisrt Redfish Discover Protocol when EFI REST EX
> protcol is discovered.
> +          // This ensures EFI REST EX is ready while
> EFI_REDFISH_DISCOVER_PROTOCOL consumer acquires
> +          // Redfish serivce over network interface.
> +
> +          Status = gBS->InstallProtocolInterface (
> +                          &EfiRedfishDiscoverProtocolHandle,
> +                          &gEfiRedfishDiscoverProtocolGuid,
> +                          EFI_NATIVE_INTERFACE,
> +                          (VOID *)&mRedfishDiscover
> +                          );
> +        } else if (EfiRedfishDiscoverProtocolHandle != NULL &&
> NewNetworkInterfaceInstalled) {
> +           Status = gBS->ReinstallProtocolInterface (
> +                            EfiRedfishDiscoverProtocolHandle,
> +                            &gEfiRedfishDiscoverProtocolGuid,
> +                            (VOID *)&mRedfishDiscover,
> +                            (VOID *)&mRedfishDiscover
> +                            );
> +           NewNetworkInterfaceInstalled = FALSE;
> +        }
> +      }
> +      return Status;
> +    } else {
> +      Index ++;
> +      if (Index == (sizeof(gRequiredProtocol) /
> sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
> +        break;
> +      }
> +      continue;
> +    }
> +  } while (Index < (sizeof(gRequiredProtocol) /
> sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL)));
> +  return EFI_UNSUPPORTED;
> +}
> +/**
> +  Close the protocol opened for Redfish discovery. This function also
> destories
> +  the network services.
> +
> +  @param[in]  ThisBindingProtocol     A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL instance.
> +  @param[in]  ControllerHandle        The handle of the controller to
> test. This handle
> +                                      must support a protocol
> interface that supplies
> +                                      an I/O abstraction to the
> driver.
> +  @param[in]  ThisRequiredProtocol    Pointer to the instance of
> REDFISH_DISCOVER_REQUIRED_PROTOCOL.
> +  @param[in]  DriverAgentHandle      Driver agent handle which used
> to open protocol earlier.
> +  @param[in]  DriverControllerHandle Driver controller handle which used
> to open protocol earlier.
> +
> +  @retval EFI_SUCCESS                Prorocol is closed successfully.
> +  @retval Others                     Prorocol is closed
> unsuccessfully.
> +
> +**/
> +EFI_STATUS
> +CloseProtocolService (
> +  IN EFI_DRIVER_BINDING_PROTOCOL  *ThisBindingProtocol,
> +  IN EFI_HANDLE  ControllerHandle,
> +  IN REDFISH_DISCOVER_REQUIRED_PROTOCOL *ThisRequiredProtocol,
> +  IN EFI_HANDLE DriverAgentHandle,
> +  IN EFI_HANDLE DriverControllerHandle
> +)
> +{
> +  EFI_STATUS Status;
> +
> +  Status = gBS->CloseProtocol (
> +                   ControllerHandle,
> +                   ThisRequiredProtocol->RequiredProtocolGuid,
> +                   DriverAgentHandle,
> +                   DriverControllerHandle
> +                   );
> +  if (!EFI_ERROR (Status)) {
> +    NetLibDestroyServiceChild(
> +      ControllerHandle,
> +      ThisBindingProtocol->ImageHandle,
> +      ThisRequiredProtocol->RequiredServiceBindingProtocolGuid,
> +      ControllerHandle
> +      );
> +  }
> +  return Status;
> +}
> +/**
> +  Stop the services on network interface.
> +
> +  @param[in]  ThisBindingProtocol  A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL instance.
> +  @param[in]  ControllerHandle     The handle of the controller to test.
> This handle
> +                                   must support a protocol
> interface that supplies
> +                                   an I/O abstraction to the driver.
> +  @retval EFI_SUCCESS              One of required protocol is found.
> +  @retval Others                   Faile to stop the services on
> network interface.
> +**/
> +EFI_STATUS
> +StopServiceOnNetworkInterface (
> +  IN EFI_DRIVER_BINDING_PROTOCOL  *ThisBindingProtocol,
> +  IN EFI_HANDLE ControllerHandle
> +  )
> +{
> +  UINT32 Index;
> +  EFI_STATUS Status;
> +  VOID *Interface;
> +  EFI_TPL OldTpl;
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *ThisNetworkInterface;
> +  EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL
> *RestExInstance;
> +
> +  for (Index = 0; Index < (sizeof (gRequiredProtocol) / sizeof
> (REDFISH_DISCOVER_REQUIRED_PROTOCOL)); Index ++) {
> +    Status = gBS->HandleProtocol (
> +                  ControllerHandle,
> +                  gRequiredProtocol [Index].RequiredProtocolGuid,
> +                  (VOID **)&Interface
> +                  );
> +    if (!EFI_ERROR (Status)) {
> +      if (gRequiredProtocol [Index].ProtocolType != ProtocolTypeRestEx) {
> +        if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
> +          return EFI_NOT_FOUND;
> +        }
> +        OldTpl = gBS->RaiseTPL
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
> +        ThisNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode
> (&mEfiRedfishDiscoverNetworkInterface);
> +        while (TRUE) {
> +          if
> (ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHan
> dle == ControllerHandle) {
> +
> +            Status = CloseProtocolService ( // Close protocol and destroy
> service.
> +                       ThisBindingProtocol,
> +                       ControllerHandle,
> +                       &gRequiredProtocol [Index],
> +
> ThisNetworkInterface->OpenDriverAgentHandle,
> +
> ThisNetworkInterface->OpenDriverControllerHandle
> +                       );
> +            if (!EFI_ERROR (Status)) {
> +              Status = DestroyRedfishNetwrokInterface
> (ThisNetworkInterface);
> +            }
> +            gBS->RestoreTPL (OldTpl);
> +            // Reinstall Redfish Discover protocol to notify network
> +            // interface change.
> +
> +            Status = gBS->ReinstallProtocolInterface (
> +                            EfiRedfishDiscoverProtocolHandle,
> +                            &gEfiRedfishDiscoverProtocolGuid,
> +                            (VOID *)&mRedfishDiscover,
> +                            (VOID *)&mRedfishDiscover
> +                            );
> +            if (EFI_ERROR (Status)) {
> +              DEBUG((DEBUG_ERROR, "%a: Reinstall
> gEfiRedfishDiscoverProtocolGuid fail.", __FUNCTION__));
> +            }
> +            return Status;
> +          }
> +          if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface,
> &ThisNetworkInterface->Entry)) {
> +            break;
> +          }
> +          ThisNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> &ThisNetworkInterface->Entry);
> +        };
> +        gBS->RestoreTPL (OldTpl);
> +      } else {
> +        if (IsListEmpty (&mEfiRedfishDiscoverRestExInstance)) {
> +          return EFI_NOT_FOUND;
> +        }
> +        OldTpl = gBS->RaiseTPL
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
> +        RestExInstance =
> (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)GetFirstNode
> (&mEfiRedfishDiscoverRestExInstance);
> +        while (TRUE) {
> +          if (RestExInstance->RestExChildHandle == ControllerHandle) {
> +            Status = CloseProtocolService ( // Close REST_EX protocol.
> +                       ThisBindingProtocol,
> +                       ControllerHandle,
> +                       &gRequiredProtocol [Index],
> +                       RestExInstance->OpenDriverAgentHandle,
> +                       RestExInstance->OpenDriverControllerHandle
> +                       );
> +            RemoveEntryList (&RestExInstance->Entry);
> +            FreePool ((VOID *)RestExInstance);
> +            mNumRestExInstance --;
> +            gBS->RestoreTPL (OldTpl);
> +            return Status;
> +          }
> +          if (IsNodeAtEnd (&mEfiRedfishDiscoverRestExInstance,
> &RestExInstance->Entry)) {
> +            break;
> +          }
> +          RestExInstance =
> (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL
> *)GetNextNode(&mEfiRedfishDiscoverRestExInstance,
> &RestExInstance->Entry);
> +        };
> +        gBS->RestoreTPL (OldTpl);
> +      }
> +    }
> +  }
> +  return EFI_NOT_FOUND;
> +}
> +/**
> +  Tests to see if this driver supports a given controller. If a child
device is
> provided,
> +  it further tests to see if this driver supports creating a handle for
the
> specified child device.
> +
> +  This function checks to see if the driver specified by This supports
the
> device specified by
> +  ControllerHandle. Drivers will typically use the device path attached
to
> +  ControllerHandle and/or the services from the bus I/O abstraction
> attached to
> +  ControllerHandle to determine if the driver supports ControllerHandle.
> This function
> +  may be called many times during platform initialization. In order to
reduce
> boot times, the tests
> +  performed by this function must be very small, and take as little time
as
> possible to execute. This
> +  function must not change the state of any hardware devices, and this
> function must be aware that the
> +  device specified by ControllerHandle may already be managed by the
> same driver or a
> +  different driver. This function must match its calls to AllocatePages()
with
> FreePages(),
> +  AllocatePool() with FreePool(), and OpenProtocol() with
CloseProtocol().
> +  Because ControllerHandle may have been previously started by the same
> driver, if a protocol is
> +  already in the opened state, then it must not be closed with
> CloseProtocol(). This is required
> +  to guarantee the state of ControllerHandle is not modified by this
> function.
> +
> +  @param[in]  This                 A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL instance.
> +  @param[in]  ControllerHandle     The handle of the controller to test.
> This handle
> +                                   must support a protocol
> interface that supplies
> +                                   an I/O abstraction to the driver.
> +  @param[in]  RemainingDevicePath  A pointer to the remaining portion
> of a device path.  This
> +                                   parameter is ignored by device
> drivers, and is optional for bus
> +                                   drivers. For bus drivers, if this
> parameter is not NULL, then
> +                                   the bus driver must determine if
> the bus controller specified
> +                                   by ControllerHandle and the
> child controller specified
> +                                   by RemainingDevicePath are
> both supported by this
> +                                   bus driver.
> +
> +  @retval EFI_SUCCESS              The device specified by
> ControllerHandle and
> +                                   RemainingDevicePath is
> supported by the driver specified by This.
> +  @retval EFI_ALREADY_STARTED      The device specified by
> ControllerHandle and
> +                                   RemainingDevicePath is already
> being managed by the driver
> +                                   specified by This.
> +  @retval EFI_ACCESS_DENIED        The device specified by
> ControllerHandle and
> +                                   RemainingDevicePath is already
> being managed by a different
> +                                   driver or an application that
> requires exclusive access.
> +                                   Currently not implemented.
> +  @retval EFI_UNSUPPORTED          The device specified by
> ControllerHandle and
> +                                   RemainingDevicePath is not
> supported by the driver specified by This.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishDiscoverDriverBindingSupported (
> +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> +  IN EFI_HANDLE                   ControllerHandle,
> +  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
> +  )
> +{
> +  return TestForRequiredProtocols (This, ControllerHandle);
> +}
> +
> +/**
> +  Starts a device controller or a bus controller.
> +
> +  The Start() function is designed to be invoked from the EFI boot
service
> ConnectController().
> +  As a result, much of the error checking on the parameters to Start()
has
> been moved into this
> +  common boot service. It is legal to call Start() from other locations,
> +  but the following calling restrictions must be followed, or the system
> behavior will not be deterministic.
> +  1. ControllerHandle must be a valid EFI_HANDLE.
> +  2. If RemainingDevicePath is not NULL, then it must be a pointer to a
> naturally aligned
> +     EFI_DEVICE_PATH_PROTOCOL.
> +  3. Prior to calling Start(), the Supported() function for the driver
specified
> by This must
> +     have been called with the same calling parameters, and Supported()
> must have returned EFI_SUCCESS.
> +
> +  @param[in]  This                 A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL instance.
> +  @param[in]  ControllerHandle     The handle of the controller to start.
> This handle
> +                                   must support a protocol
> interface that supplies
> +                                   an I/O abstraction to the driver.
> +  @param[in]  RemainingDevicePath  A pointer to the remaining portion
> of a device path.  This
> +                                   parameter is ignored by device
> drivers, and is optional for bus
> +                                   drivers. For a bus driver, if this
> parameter is NULL, then handles
> +                                   for all the children of Controller
> are created by this driver.
> +                                   If this parameter is not NULL
> and the first Device Path Node is
> +                                   not the End of Device Path Node,
> then only the handle for the
> +                                   child device specified by the first
> Device Path Node of
> +                                   RemainingDevicePath is created
> by this driver.
> +                                   If the first Device Path Node of
> RemainingDevicePath is
> +                                   the End of Device Path Node, no
> child handle is created by this
> +                                   driver.
> +
> +  @retval EFI_SUCCESS              The device was started.
> +  @retval EFI_DEVICE_ERROR         The device could not be started
> due to a device error.Currently not implemented.
> +  @retval EFI_OUT_OF_RESOURCES     The request could not be
> completed due to a lack of resources.
> +  @retval Others                   The driver failded to start the
> device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishDiscoverDriverBindingStart (
> +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> +  IN EFI_HANDLE                   ControllerHandle,
> +  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
> +  )
> +{
> +  return BuildupNetworkInterface (This, ControllerHandle);
> +}
> +
> +/**
> +  Stops a device controller or a bus controller.
> +
> +  The Stop() function is designed to be invoked from the EFI boot service
> DisconnectController().
> +  As a result, much of the error checking on the parameters to Stop() has
> been moved
> +  into this common boot service. It is legal to call Stop() from other
locations,
> +  but the following calling restrictions must be followed, or the system
> behavior will not be deterministic.
> +  1. ControllerHandle must be a valid EFI_HANDLE that was used on a
> previous call to this
> +     same driver's Start() function.
> +  2. The first NumberOfChildren handles of ChildHandleBuffer must all be
a
> valid
> +     EFI_HANDLE. In addition, all of these handles must have been created
> in this driver's
> +     Start() function, and the Start() function must have called
> OpenProtocol() on
> +     ControllerHandle with an Attribute of
> EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
> +
> +  @param[in]  This              A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL instance.
> +  @param[in]  ControllerHandle  A handle to the device being stopped.
> The handle must
> +                                support a bus specific I/O protocol
> for the driver
> +                                to use to stop the device.
> +  @param[in]  NumberOfChildren  The number of child device handles in
> ChildHandleBuffer.
> +  @param[in]  ChildHandleBuffer An array of child handles to be freed.
> May be NULL
> +                                if NumberOfChildren is 0.
> +
> +  @retval EFI_SUCCESS           The device was stopped.
> +  @retval EFI_DEVICE_ERROR      The device could not be stopped due
> to a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishDiscoverDriverBindingStop (
> +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> +  IN EFI_HANDLE                   ControllerHandle,
> +  IN UINTN                        NumberOfChildren,
> +  IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
> +  )
> +{
> +  return StopServiceOnNetworkInterface (This, ControllerHandle);
> +}
> +
> +EFI_DRIVER_BINDING_PROTOCOL gRedfishDiscoverDriverBinding = {
> +  RedfishDiscoverDriverBindingSupported,
> +  RedfishDiscoverDriverBindingStart,
> +  RedfishDiscoverDriverBindingStop,
> +  REDFISH_DISCOVER_VERSION,
> +  NULL,
> +  NULL
> +};
> +
> +/**
> +  This is the declaration of an EFI image entry point.
> +
> +  @param  ImageHandle           The firmware allocated handle for
> the UEFI image.
> +  @param  SystemTable           A pointer to the EFI System Table.
> +
> +  @retval EFI_SUCCESS           The operation completed successfully.
> +  @retval Others                An unexpected error occurred.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishDiscoverEntryPoint (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  Status = EFI_SUCCESS;
> +  InitializeListHead (&mRedfishDiscoverList);
> +  InitializeListHead (&mRedfishInstanceList);
> +  InitializeListHead (&mEfiRedfishDiscoverNetworkInterface);
> +  InitializeListHead (&mEfiRedfishDiscoverRestExInstance);
> +  //
> +  // Install binding protoocl to obtain UDP and REST EX protocol.
> +  //
> +  Status = EfiLibInstallDriverBindingComponentName2 (
> +             ImageHandle,
> +             SystemTable,
> +             &gRedfishDiscoverDriverBinding,
> +             ImageHandle,
> +             &gRedfishDiscoverComponentName,
> +             &gRedfishDiscoverComponentName2
> +             );
> +  return Status;
> +}
> +
> +/**
> +  This is the unload handle for Redfish discover module.
> +
> +  Disconnect the driver specified by ImageHandle from all the devices in
the
> handle database.
> +  Uninstall all the protocols installed in the driver entry point.
> +
> +  @param[in] ImageHandle           The drivers' driver image.
> +
> +  @retval    EFI_SUCCESS           The image is unloaded.
> +  @retval    Others                Failed to unload the image.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishDiscoverUnload (
> +  IN EFI_HANDLE ImageHandle
> +  )
> +{
> +  EFI_STATUS Status;
> +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *ThisNetworkInterface;
> +
> +  Status = EFI_SUCCESS;
> +  // Destroy all network interfaces found by EFI Redfish Discover driver
and
> +  // stop services created for Redfish Discover.
> +
> +  while (!IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
> +    ThisNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode
> (&mEfiRedfishDiscoverNetworkInterface);
> +    StopServiceOnNetworkInterface (&gRedfishDiscoverDriverBinding,
> ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHan
> dle);
> +  };
> +  // Disconnect EFI Redfish discover driver controller to notify the
> +  // clinet which uses .EFI Redfish discover protocol.
> +
> +  if (EfiRedfishDiscoverProtocolHandle != NULL) {
> +    //
> +    // Notify user EFI_REDFISH_DISCOVER_PROTOCOL is unloaded.
> +    //
> +    gBS->DisconnectController (EfiRedfishDiscoverProtocolHandle, NULL,
> NULL);
> +    Status = gBS->UninstallProtocolInterface(
> +                    EfiRedfishDiscoverProtocolHandle,
> +                    &gEfiRedfishDiscoverProtocolGuid,
> +                    (VOID *)&mRedfishDiscover
> +                    );
> +  }
> +  return Status;
> +}
> diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
> b/RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
> new file mode 100644
> index 0000000000..f3ad36ec3a
> --- /dev/null
> +++ b/RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
> @@ -0,0 +1,118 @@
> +/** @file
> +  RedfishSmbiosHostInterface.c
> +
> +  Discover Redfish SMBIOS Host Interface.
> +
> +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "RedfishDiscoverInternal.h"
> +
> +SMBIOS_TABLE_TYPE42  *mType42Record;
> +
> +/**
> +  The function gets information reported in Redfish Host Interface.
> +
> +  It simply frees the packet.
> +
> +  @param[in]  Smbios           SMBIOS protocol.
> +  @param[out] DeviceDescriptor Pointer to REDFISH_INTERFACE_DATA.
> +  @param[out] ProtocolData     Pointer to
> REDFISH_OVER_IP_PROTOCOL_DATA.
> +
> +  @retval EFI_SUCCESS    Get host interface succesfully.
> +  @retval Otherwise      Fail to tet host interface.
> +
> +**/
> +EFI_STATUS
> +RedfishGetHostInterfaceProtocolData (
> +  IN EFI_SMBIOS_PROTOCOL              *Smbios,
> +  OUT REDFISH_INTERFACE_DATA          **DeviceDescriptor,
> +  OUT REDFISH_OVER_IP_PROTOCOL_DATA   **ProtocolData
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  EFI_SMBIOS_HANDLE                 SmbiosHandle;
> +  EFI_SMBIOS_TABLE_HEADER           *Record;
> +  UINT16                            Offset;
> +  UINT8                             *RecordTmp;
> +  UINT8                             ProtocolLength;
> +  UINT8                             SpecificDataLen;
> +
> +  if ((Smbios == NULL) || (ProtocolData == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
> +  Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record,
> NULL);
> +  while (!EFI_ERROR (Status) && SmbiosHandle !=
> SMBIOS_HANDLE_PI_RESERVED) {
> +    if (Record->Type ==
> SMBIOS_TYPE_MANAGEMENT_CONTROLLER_HOST_INTERFACE) {
> +      //
> +      // Check Interface Type, should be Network Host Interface = 40h
> +      //
> +      mType42Record = (SMBIOS_TABLE_TYPE42 *) Record;
> +      if (mType42Record->InterfaceType ==
> MCHostInterfaceTypeNetworkHostInterface) {
> +        ASSERT (Record->Length >= 9);
> +        Offset = 5;
> +        RecordTmp = (UINT8 *) Record + Offset;
> +        //
> +        // Get interface specific data length.
> +        //
> +        SpecificDataLen = *RecordTmp;
> +        Offset += 1;
> +        RecordTmp = (UINT8 *) Record + Offset;
> +
> +        //
> +        // Check Device Type, only PCI/PCIe Network Interface v2 is
> supported now.
> +        //
> +        if (*RecordTmp ==
> REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2) {
> +          ASSERT (SpecificDataLen == sizeof
> (PCI_OR_PCIE_INTERFACE_DEVICE_DESCRIPTOR_V2) + 1);
> +          *DeviceDescriptor = (REDFISH_INTERFACE_DATA *)RecordTmp;
> +          Offset = Offset + SpecificDataLen;
> +          RecordTmp = (UINT8 *) Record + Offset;
> +          //
> +          // Check Protocol count. if > 1, only use the first protocol.
> +          //
> +          ASSERT (*RecordTmp == 1);
> +          Offset += 1;
> +          RecordTmp = (UINT8 *) Record + Offset;
> +          //
> +          // Check protocol identifier.
> +          //
> +          if (*RecordTmp == MCHostInterfaceProtocolTypeRedfishOverIP)
> {
> +            Offset += 1;
> +            RecordTmp = (UINT8 *) Record + Offset;
> +            ProtocolLength = *RecordTmp;
> +
> +            Offset += 1;
> +            RecordTmp = (UINT8 *) Record + Offset;
> +
> +            //
> +            // This SMBIOS record is invalid, if the length of protocol
> specific data for
> +            // Redfish Over IP protocol is wrong.
> +            //
> +            if ((*(RecordTmp + 90) + sizeof
> (REDFISH_OVER_IP_PROTOCOL_DATA) - 1) != ProtocolLength) {
> +              return EFI_SECURITY_VIOLATION;
> +            }
> +
> +            Offset += ProtocolLength;
> +            //
> +            // This SMBIOS record is invalid, if the length is smaller
than
> the offset.
> +            //
> +            if (Offset > mType42Record->Hdr.Length) {
> +              return EFI_SECURITY_VIOLATION;
> +            }
> +            *ProtocolData = (REDFISH_OVER_IP_PROTOCOL_DATA
> *)RecordTmp;
> +            return EFI_SUCCESS;
> +          }
> +        }
> +      }
> +    }
> +    Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record,
> NULL);
> +  }
> +
> +  *ProtocolData = NULL;
> +  return EFI_NOT_FOUND;
> +}
> --
> 2.17.1
> 
> 
> 
> 
> 





-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#73762): https://edk2.groups.io/g/devel/message/73762
Mute This Topic: https://groups.io/mt/81909222/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-


Re: [edk2-devel] [PATCH] RedfishPkg/RedfishDiscoverDxe: EFI Redfish Discover Protocol
Posted by Abner Chang 3 years ago
BZ was created for this.
https://bugzilla.tianocore.org/show_bug.cgi?id=2906

I will update the commit message with the feedback from reviewer if any.
Thanks

> -----Original Message-----
> From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> gaoliming
> Sent: Wednesday, April 7, 2021 1:20 PM
> To: devel@edk2.groups.io; Chang, Abner (HPS SW/FW Technologist)
> <abner.chang@hpe.com>
> Cc: Wang, Nickle (HPS SW) <nickle.wang@hpe.com>; 'Jiaxin Wu'
> <jiaxin.wu@intel.com>; 'Siyuan Fu' <siyuan.fu@intel.com>; 'Fan Wang'
> <fan.wang@intel.com>; 'Jiewen Yao' <jiewen.yao@intel.com>
> Subject: 回复: [edk2-devel] [PATCH] RedfishPkg/RedfishDiscoverDxe: EFI
> Redfish Discover Protocol
> 
> Abner:
>   This is new feature. Can you submit one BZ for it?
> 
> Thanks
> Liming
> > -----邮件原件-----
> > 发件人: devel@edk2.groups.io <devel@edk2.groups.io> 代表 Abner
> Chang
> > 发送时间: 2021年3月26日 12:54
> > 收件人: devel@edk2.groups.io
> > 抄送: Nickle Wang <nickle.wang@hpe.com>; Jiaxin Wu
> > <jiaxin.wu@intel.com>; Siyuan Fu <siyuan.fu@intel.com>; Fan Wang
> > <fan.wang@intel.com>; Jiewen Yao <jiewen.yao@intel.com>
> > 主题: [edk2-devel] [PATCH] RedfishPkg/RedfishDiscoverDxe: EFI Redfish
> > Discover Protocol
> >
> > EDK2 EFI Redfish Discover Protocol implementation. Refer to UEFI spec 2.9
> > section 31.1.
> >
> > Signed-off-by: Abner Chang <abner.chang@hpe.com>
> > Cc: Nickle Wang <nickle.wang@hpe.com>
> > Cc: Jiaxin Wu <jiaxin.wu@intel.com>
> > Cc: Siyuan Fu <siyuan.fu@intel.com>
> > Cc: Fan Wang <fan.wang@intel.com>
> > Cc: Jiewen Yao <jiewen.yao@intel.com>
> > ---
> >  RedfishPkg/RedfishComponents.dsc.inc          |    3 +-
> >  RedfishPkg/Redfish.fdf.inc                    |    3 +-
> >  .../RedfishDiscoverDxe/RedfishDiscoverDxe.inf |   55 +
> >  .../RedfishDiscoverInternal.h                 |  234 ++
> >  RedfishPkg/RedfishDiscoverDxe/ComponentName.c |  218 ++
> >  .../RedfishDiscoverDxe/RedfishDiscoverDxe.c   | 1910
> > +++++++++++++++++
> >  .../RedfishSmbiosHostInterface.c              |  118 +
> >  7 files changed, 2539 insertions(+), 2 deletions(-)
> >  create mode 100644
> RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
> >  create mode 100644
> > RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
> >  create mode 100644 RedfishPkg/RedfishDiscoverDxe/ComponentName.c
> >  create mode 100644
> RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
> >  create mode 100644
> > RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
> >
> > diff --git a/RedfishPkg/RedfishComponents.dsc.inc
> > b/RedfishPkg/RedfishComponents.dsc.inc
> > index 08f1d3bc32..6f3b055aba 100644
> > --- a/RedfishPkg/RedfishComponents.dsc.inc
> > +++ b/RedfishPkg/RedfishComponents.dsc.inc
> > @@ -6,7 +6,7 @@
> >  # of EDKII Redfish drivers according to the value of flags described in
> >  # "RedfishDefines.dsc.inc".
> >  #
> > -# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
> > +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> >  #
> >  #    SPDX-License-Identifier: BSD-2-Clause-Patent
> >  #
> > @@ -17,4 +17,5 @@
> >    RedfishPkg/RedfishHostInterfaceDxe/RedfishHostInterfaceDxe.inf
> >    RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf
> >    RedfishPkg/RedfishCredentialDxe/RedfishCredentialDxe.inf
> > +  RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
> >  !endif
> > diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc
> > index a64fd119a9..205c3101c0 100644
> > --- a/RedfishPkg/Redfish.fdf.inc
> > +++ b/RedfishPkg/Redfish.fdf.inc
> > @@ -5,7 +5,7 @@
> >  # by using "!include RedfishPkg/RedfisLibs.fdf.inc" to specify the module
> > instances
> >  # to be built in the firmware volume.
> >  #
> > -# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
> > +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> >  #
> >  #    SPDX-License-Identifier: BSD-2-Clause-Patent
> >  #
> > @@ -15,4 +15,5 @@
> >    INF RedfishPkg/RedfishHostInterfaceDxe/RedfishHostInterfaceDxe.inf
> >    INF RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf
> >    INF RedfishPkg/RedfishCredentialDxe/RedfishCredentialDxe.inf
> > +  INF RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
> >  !endif
> > diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
> > b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
> > new file mode 100644
> > index 0000000000..345bacf44d
> > --- /dev/null
> > +++ b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
> > @@ -0,0 +1,55 @@
> > +## @file
> > +#  Implementation of EFI_REDFISH_DISCOVER_PROTOCOL interfaces.
> > +#
> > +#  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> > +#
> > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +##
> > +
> > +[Defines]
> > +  INF_VERSION               = 0x0001001b
> > +  BASE_NAME                 = RedfishDiscoverDxe
> > +  FILE_GUID                 =
> > 28A76FE5-43D7-48A3-9714-C1B7BDD6DFB6
> > +  MODULE_TYPE               = UEFI_DRIVER
> > +  VERSION_STRING            = 1.0
> > +  ENTRY_POINT               = RedfishDiscoverEntryPoint
> > +  UNLOAD_IMAGE              = RedfishDiscoverUnload
> > +
> > +[Packages]
> > +  MdePkg/MdePkg.dec
> > +  MdeModulePkg/MdeModulePkg.dec
> > +  NetworkPkg/NetworkPkg.dec
> > +  RedfishPkg/RedfishPkg.dec
> > +
> > +[Sources]
> > +  ComponentName.c
> > +  RedfishDiscoverDxe.c
> > +  RedfishSmbiosHostInterface.c
> > +  RedfishDiscoverInternal.h
> > +
> > +[LibraryClasses]
> > +  BaseLib
> > +  BaseMemoryLib
> > +  DebugLib
> > +  MemoryAllocationLib
> > +  PrintLib
> > +  RestExLib
> > +  UefiLib
> > +  UefiBootServicesTableLib
> > +  UefiDriverEntryPoint
> > +
> > +[Protocols]
> > +  gEfiRestExServiceBindingProtocolGuid            ## Consuming
> > +  gEfiRestExProtocolGuid                          ## Consuming
> > +  gEfiTcp4ServiceBindingProtocolGuid              ## Consuming
> > +  gEfiTcp4ProtocolGuid                            ## Consuming
> > +  gEfiTcp6ServiceBindingProtocolGuid              ## Consuming
> > +  gEfiTcp6ProtocolGuid                            ## Consuming
> > +  gEfiRedfishDiscoverProtocolGuid                 ## Prodcuing
> > +  gEfiSmbiosProtocolGuid                          ## Consuming
> > +  gEfiDriverBindingProtocolGuid                   ## Consuming
> > +
> > +[Pcd]
> > +  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishDiscoverAccessModeInBand
> ##
> > CONSUMES
> > +
> > diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
> > b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
> > new file mode 100644
> > index 0000000000..cf69d9231a
> > --- /dev/null
> > +++ b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
> > @@ -0,0 +1,234 @@
> > +/** @file
> > +  This file defines the EFI Redfish Discover Protocol interface.
> > +
> > +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> > +
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef EFI_REDFISH_DISCOVER_INTERNAL_H_
> > +#define EFI_REDFISH_DISCOVER_INTERNAL_H_
> > +
> > +#include <Uefi.h>
> > +
> > +#include <Protocol/ComponentName.h>
> > +#include <Protocol/ComponentName2.h>
> > +#include <Protocol/DriverBinding.h>
> > +#include <Protocol/RedfishDiscover.h>
> > +#include <Protocol/Smbios.h>
> > +#include <Protocol/Tcp4.h>
> > +#include <Protocol/Tcp6.h>
> > +
> > +#include <Library/BaseLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/NetLib.h>
> > +#include <Library/PrintLib.h>
> > +#include <Library/RestExLib.h>
> > +#include <Library/UefiLib.h>
> > +#include <Library/UefiBootServicesTableLib.h>
> > +#include <Library/UefiDriverEntryPoint.h>
> > +
> > +#include <IndustryStandard/RedfishHostInterface.h>
> > +
> > +#define REDFISH_DISCOVER_VERSION  0x00010000
> > +#define EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL TPL_NOTIFY
> > +
> > +//
> > +//GUID definitions
> > +//
> > +
> > +#define EFI_REDFISH_DISCOVER_TCP4_INSTANCE_GUID \
> > +  { \
> > +    0xfbab97a4, 0x4c6a, 0xf8e8, { 0xf2, 0x25, 0x42, 0x8a, 0x80, 0x3f,
> 0xb6,
> > 0xaa } \
> > +  }
> > +
> > +#define EFI_REDFISH_DISCOVER_TCP6_INSTANCE_GUID \
> > +  { \
> > +    0xbe513b6d, 0x41c1, 0x96Ed, { 0x8d, 0xaf, 0x3e, 0x89, 0xc5, 0xf5,
> 0x02,
> > 0x25 } \
> > +  }
> > +
> > +#define EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_GUID \
> > +  { \
> > +    0xc44a6076, 0xd42a, 0x4d54, { 0x85, 0x6d, 0x98, 0x8a, 0x85, 0x8f,
> 0xa1,
> > 0x11 } \
> > +  }
> > +
> > +extern EFI_COMPONENT_NAME_PROTOCOL
> > gRedfishDiscoverComponentName;
> > +extern EFI_COMPONENT_NAME2_PROTOCOL
> > gRedfishDiscoverComponentName2;
> > +extern EFI_UNICODE_STRING_TABLE
> > *gRedfishDiscoverControllerNameTable;
> > +
> > +//
> > +// Enumeration of network protocols
> > +// required for the Redfish service discovery.
> > +//
> > +typedef enum {
> > +  ProtocolTypeTcp4 = 0, ///< Network protocol TCPv4.
> > +  ProtocolTypeTcp6,     ///< Network protocol TCCv6.
> > +  ProtocolTypeRestEx,   ///< REST EX over network protocol.
> > +  MaxProtocolType
> > +} NETWORK_INTERFACE_PROTOCOL_TYPE;
> > +
> > +//
> > +// Network protocol information installed on
> > +// the network interface.
> > +//
> > +typedef struct {
> > +  EFI_GUID ProtocolGuid;                ///< Network protocol GUID.
> > +  EFI_GUID ProtocolServiceGuid;         ///< Network protocol service
> > GUID.
> > +  UINT32   ProtocolDiscoverId;          ///< The identifier installed on
> > network protocol handle.
> > +  EFI_HANDLE ProtocolControllerHandle;  ///< The controller handle on
> > network protocol.
> > +  VOID *NetworkProtocolInterface;       ///< The protocol interface of
> > network protocol.
> > +} REDFISH_DISCOVER_NETWORK_INTERFACE_PROTOCOL;
> > +
> > +//
> > +// Internal structure used to maintain network
> > +// interface properties.
> > +//
> > +typedef struct {
> > +  LIST_ENTRY      Entry;                        ///< Link list
> > entry.
> > +  EFI_HANDLE      OpenDriverAgentHandle;        ///< The agent to
> > open network protocol.
> > +  EFI_HANDLE      OpenDriverControllerHandle;   ///< The controller
> > handle to open network protocol.
> > +  UINTN           HwAddressSize;                ///< The size of
> > network interface hardware address.
> > +  EFI_MAC_ADDRESS MacAddress;                   ///< MAC
> > address of network interface.
> > +  CHAR16          *StrMacAddr;                  ///< String to
> > MAC address of network interface.
> > +  BOOLEAN         GotSubnetInfo;                ///< Indicates sub
> > net information is retrieved.
> > +  EFI_IP_ADDRESS  SubnetAddr;                   ///< Subnet ID.
> > +  EFI_IP_ADDRESS  SubnetMask;                   ///< Subnet mask
> > (IPv4 only)
> > +  UINT8           SubnetPrefixLength;           ///< Subnet prefix.
> > +  UINT16          VlanId;                       ///< VLAN ID
> > +  UINT32          SubnetAddrInfoIPv6Number;     ///< IPv6 address
> > info number.
> > +  EFI_IP6_ADDRESS_INFO *SubnetAddrInfoIPv6;     ///< IPv6 address
> > info.
> > +  //
> > +  // Network interface protocol and REST EX infor.
> > +  //
> > +  UINT32          NetworkProtocolType;          ///< Network
> > protocol type. Refer to
> > +                                                ///<
> > NETWORK_INTERFACE_PROTOCOL_TYPE.
> > +  REDFISH_DISCOVER_NETWORK_INTERFACE_PROTOCOL
> > NetworkInterfaceProtocolInfo; ///< Network interface protocol
> information.
> > +  EFI_HANDLE      RestExHandle;                 ///< REST EX
> > handle associated with this network interface.
> > +} EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL;
> > +
> > +//
> > +// Internal structure used to maintain REST EX properties.
> > +//
> > +typedef struct {
> > +    LIST_ENTRY      Entry;                          ///< Link list
> > entry.
> > +    EFI_HANDLE      OpenDriverAgentHandle;          ///< The
> > agent to open network protocol.
> > +    EFI_HANDLE      OpenDriverControllerHandle;     ///< The
> > controller handle to open network protocol.
> > +    EFI_HANDLE      RestExChildHandle;              ///< The child
> > handle created throught REST EX Service Protocol.
> > +    EFI_HANDLE      RestExControllerHandle;         ///< The
> > controller handle which provide REST EX protocol.
> > +    EFI_REST_EX_PROTOCOL *RestExProtocolInterface;  ///< Pointer to
> > EFI_REST_EX_PROTOCOL.
> > +    UINT32          RestExId;                       ///< The
> > identifier installed on REST EX controller handle.
> > +} EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL;
> > +
> > +/**
> > +  This function to get subnet information.
> > +
> > +  @param[in]            ImageHandle  EFI handle with this image.
> > +  @param[in]            Instance  Instance of Network interface.
> > +  @retval EFI_STATUS    Get subnet information successfully.
> > +  @retval Otherwise     Fail to get subnet information.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EFI_REDFISH_DISCOVER_GET_SUBNET_INFO)(
> > +  IN EFI_HANDLE ImageHandle,
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
> > +);
> > +
> > +//
> > +// The require network protocol matrix.
> > +//
> > +typedef struct {
> > +  UINT32   ProtocolType;                                ///<
> > Network protocol type,
> > +                                                        ///<
> > Refer to NETWORK_INTERFACE_PROTOCOL_TYPE.
> > +  CHAR16   *ProtocolName;                               ///<
> > Protocol name.
> > +  EFI_GUID *RequiredProtocolGuid;                       ///<
> > Network protocol interface GUID.
> > +  EFI_GUID *RequiredServiceBindingProtocolGuid;         ///< Network
> > protocol service GUID.
> > +  EFI_GUID *DiscoveredProtocolGuid;                     ///<
> > Protocol interface GUID use to install identifier.
> > +  EFI_REDFISH_DISCOVER_GET_SUBNET_INFO GetSubnetInfo;   ///<
> > Function of getting subnet information.
> > +} REDFISH_DISCOVER_REQUIRED_PROTOCOL;
> > +
> > +//
> > +// Link list of Redfish discover instance.
> > +//
> > +typedef struct {
> > +  LIST_ENTRY  NextInstance;                             ///<
> > Next list.
> > +  EFI_REDFISH_DISCOVERED_INSTANCE *Instance;            ///<
> > Pointer to EFI_REDFISH_DISCOVERED_INSTANCE.
> > +} EFI_REDFISH_DISCOVERED_INTERNAL_LIST;
> > +
> > +//
> > +// Internal structure of Redfish discover instance.
> > +//
> > +typedef struct {
> > +  LIST_ENTRY  Entry;                                    ///<
> > Link list entry.
> > +  EFI_HANDLE  Owner;                                    ///<
> > The owner owns this Redfish service discovery.
> > +                                                        ///<
> > It's the EFI image handle of driver uses
> > +                                                        ///<
> > EFI Redfish Discover Protocol.
> > +  EFI_REDFISH_DISCOVER_FLAG DiscoverFlags;              ///<
> > EFI_REDFISH_DISCOVER_FLAG
> > +  EFI_REDFISH_DISCOVERED_TOKEN *DiscoverToken;          ///<
> > Token used to signal when Redfish service is discovered.
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *NetworkInterface; ///<
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > +
> > ///< instance used to discover Redfish service.
> > +  //
> > +  // Below for Host insterface discovery.
> > +  //
> > +  BOOLEAN         HostIntfValidation;                   ///<
> > Indicates whether to validate Redfish Host interface.
> > +  EFI_IP_ADDRESS  TargetIpAddress;                      ///<
> > Target IP address reported in Redfish Host interface.
> > +} EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE;
> > +
> > +/**
> > +  The function adds a new foudn Redfish service to internal list and
> > +  notify clinet.
> > +
> > +  It simply frees the packet.
> > +
> > +  @param[in]  Instance
> > EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
> > +  @param[in]  RedfishVersion        Redfish version.
> > +  @param[in]  RedfishLocation       Redfish location.
> > +  @param[in]  Uuid                  Service UUID string.
> > +  @param[in]  Os                    OS string.
> > +  @param[in]  OsVer                 OS version string.
> > +  @param[in]  Product               Product string.
> > +  @param[in]  ProductVer            Product verison string.
> > +  @param[in]  UseHttps              Redfish service requires secured
> > connection.
> > +  @retval EFI_SUCCESS               Redfish service is added to list
> > successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +AddAndSignalNewRedfishService (
> > +  IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
> > +  IN UINTN *RedfishVersion OPTIONAL,
> > +  IN CHAR8 *RedfishLocation OPTIONAL,
> > +  IN CHAR8 *Uuid  OPTIONAL,
> > +  IN CHAR8 *Os  OPTIONAL,
> > +  IN CHAR8 *OsVer  OPTIONAL,
> > +  IN CHAR8 *Product  OPTIONAL,
> > +  IN CHAR8 *ProductVer  OPTIONAL,
> > +  IN BOOLEAN UseHttps
> > +  );
> > +
> > +/**
> > +  The function gets information reported in Redfish Host Interface.
> > +
> > +  It simply frees the packet.
> > +
> > +  @param[in]  Smbios           SMBIOS protocol.
> > +  @param[out] DeviceDescriptor Pointer to REDFISH_INTERFACE_DATA.
> > +  @param[out] ProtocolData     Pointer to
> > REDFISH_OVER_IP_PROTOCOL_DATA.
> > +
> > +  @retval EFI_SUCCESS    Get host interface succesfully.
> > +  @retval Otherwise      Fail to tet host interface.
> > +
> > +**/
> > +EFI_STATUS
> > +RedfishGetHostInterfaceProtocolData (
> > +  IN EFI_SMBIOS_PROTOCOL              *Smbios,
> > +  OUT REDFISH_INTERFACE_DATA          **DeviceDescriptor,
> > +  OUT REDFISH_OVER_IP_PROTOCOL_DATA   **ProtocolData
> > +  );
> > +
> > +extern EFI_GUID gRedfishDiscoverTcp4Instance;
> > +extern EFI_GUID gRedfishDiscoverTcp6Instance;
> > +extern EFI_GUID gRedfishDiscoverRestEXInstance;
> > +#endif
> > diff --git a/RedfishPkg/RedfishDiscoverDxe/ComponentName.c
> > b/RedfishPkg/RedfishDiscoverDxe/ComponentName.c
> > new file mode 100644
> > index 0000000000..adad2504bc
> > --- /dev/null
> > +++ b/RedfishPkg/RedfishDiscoverDxe/ComponentName.c
> > @@ -0,0 +1,218 @@
> > +/** @file
> > +  Implementation of EFI_COMPONENT_NAME_PROTOCOL and
> > EFI_COMPONENT_NAME2_PROTOCOL protocol.
> > +  for EFI Refish Discover Protocol
> > +
> > +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> > +
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include "RedfishDiscoverInternal.h"
> > +
> > +//
> > +// EFI Component Name Functions
> > +//
> > +/**
> > +  Retrieves a Unicode string that is the user-readable name of the EFI
> > Driver.
> > +
> > +  @param[in]  This       A pointer to the
> > EFI_COMPONENT_NAME_PROTOCOL instance.
> > +  @param[in]  Language   A pointer to a three-character ISO 639-2
> > language identifier.
> > +                         This is the language of the driver name that
> > that the caller
> > +                         is requesting, and it must match one of the
> > languages specified
> > +                         in SupportedLanguages.  The number of
> > languages supported by a
> > +                         driver is up to the driver writer.
> > +  @param[out] DriverName A pointer to the Unicode string to return.
> > This Unicode string
> > +                         is the name of the driver specified by This in
> > the language
> > +                         specified by Language.
> > +
> > +  @retval EFI_SUCCESS           The Unicode string for the Driver
> > specified by This
> > +                                and the language specified by
> > Language was returned
> > +                                in DriverName.
> > +  @retval EFI_INVALID_PARAMETER Language is NULL.
> > +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> > +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> > support the
> > +                                language specified by Language.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishDiscoverComponentNameGetDriverName (
> > +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> > +  IN  CHAR8                        *Language,
> > +  OUT CHAR16                       **DriverName
> > +  );
> > +
> > +/**
> > +  Retrieves a Unicode string that is the user readable name of the
> controller
> > +  that is being managed by an EFI Driver.
> > +
> > +  @param[in]  This             A pointer to the
> > EFI_COMPONENT_NAME_PROTOCOL instance.
> > +  @param[in]  ControllerHandle The handle of a controller that the driver
> > specified by
> > +                               This is managing.  This handle
> > specifies the controller
> > +                               whose name is to be returned.
> > +  @param[in]  ChildHandle      The handle of the child controller to
> > retrieve the name
> > +                               of.  This is an optional parameter
> > that may be NULL.  It
> > +                               will be NULL for device drivers.  It
> > will also be NULL
> > +                               for a bus drivers that wish to retrieve
> > the name of the
> > +                               bus controller.  It will not be NULL
> > for a bus driver
> > +                               that wishes to retrieve the name of a
> > child controller.
> > +  @param[in]  Language         A pointer to a three character ISO
> > 639-2 language
> > +                               identifier.  This is the language of the
> > controller name
> > +                               that the caller is requesting, and it
> > must match one
> > +                               of the languages specified in
> > SupportedLanguages.  The
> > +                               number of languages supported by a
> > driver is up to the
> > +                               driver writer.
> > +  @param[out]  ControllerName  A pointer to the Unicode string to
> > return.  This Unicode
> > +                               string is the name of the controller
> > specified by
> > +                               ControllerHandle and ChildHandle in
> > the language specified
> > +                               by Language, from the point of view
> > of the driver specified
> > +                               by This.
> > +
> > +  @retval EFI_SUCCESS           The Unicode string for the
> > user-readable name in the
> > +                                language specified by Language for
> > the driver
> > +                                specified by This was returned in
> > DriverName.
> > +  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> > +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> > valid EFI_HANDLE.
> > +  @retval EFI_INVALID_PARAMETER Language is NULL.
> > +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> > +  @retval EFI_UNSUPPORTED       The driver specified by This is not
> > currently managing
> > +                                the controller specified by
> > ControllerHandle and
> > +                                ChildHandle.
> > +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> > support the
> > +                                language specified by Language.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishDiscoverComponentNameGetControllerName (
> > +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> > +  IN  EFI_HANDLE                    ControllerHandle,
> > +  IN  EFI_HANDLE                    ChildHandle
> > OPTIONAL,
> > +  IN  CHAR8                         *Language,
> > +  OUT CHAR16                        **ControllerName
> > +  );
> > +
> > +
> > +///
> > +/// Component Name Protocol instance
> > +///
> > +GLOBAL_REMOVE_IF_UNREFERENCED
> > +EFI_COMPONENT_NAME_PROTOCOL
> gRedfishDiscoverComponentName
> > = {
> > +  RedfishDiscoverComponentNameGetDriverName,
> > +  RedfishDiscoverComponentNameGetControllerName,
> > +  "eng"
> > +};
> > +
> > +///
> > +/// Component Name 2 Protocol instance
> > +///
> > +GLOBAL_REMOVE_IF_UNREFERENCED
> > +EFI_COMPONENT_NAME2_PROTOCOL
> > gRedfishDiscoverComponentName2 = {
> > +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)
> > RedfishDiscoverComponentNameGetDriverName,
> > +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)
> > RedfishDiscoverComponentNameGetControllerName,
> > +  "en"
> > +};
> > +
> > +///
> > +/// Table of driver names
> > +///
> > +GLOBAL_REMOVE_IF_UNREFERENCED
> > +EFI_UNICODE_STRING_TABLE mRedfishDiscoverDriverNameTable[] = {
> > +  { "eng;en", (CHAR16 *)L"Redfish Discover UEFI Driver" },
> > +  { NULL, NULL }
> > +};
> > +
> > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> > *gRedfishDiscoverControllerNameTable = NULL;
> > +
> > +/**
> > +  Retrieves a Unicode string that is the user-readable name of the EFI
> > Driver.
> > +
> > +  @param[in]  This        A pointer to the
> > EFI_COMPONENT_NAME_PROTOCOL instance.
> > +  @param[in]  Language    A pointer to a three-character ISO 639-2
> > language identifier.
> > +                          This is the language of the driver name that
> > that the caller
> > +                          is requesting, and it must match one of the
> > languages specified
> > +                          in SupportedLanguages.  The number of
> > languages supported by a
> > +                          driver is up to the driver writer.
> > +  @param[out]  DriverName A pointer to the Unicode string to return.
> > This Unicode string
> > +                          is the name of the driver specified by This in
> > the language
> > +                          specified by Language.
> > +
> > +  @retval EFI_SUCCESS           The Unicode string for the Driver
> > specified by This
> > +                                and the language specified by
> > Language was returned
> > +                                in DriverName.
> > +  @retval EFI_INVALID_PARAMETER Language is NULL.
> > +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> > +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> > support the
> > +                                language specified by Language.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishDiscoverComponentNameGetDriverName (
> > +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> > +  IN  CHAR8                        *Language,
> > +  OUT CHAR16                       **DriverName
> > +  )
> > +{
> > +  return LookupUnicodeString2 (
> > +           Language,
> > +           This->SupportedLanguages,
> > +           mRedfishDiscoverDriverNameTable,
> > +           DriverName,
> > +           (BOOLEAN)(This == &gRedfishDiscoverComponentName)
> > +           );
> > +}
> > +
> > +/**
> > +  Retrieves a Unicode string that is the user readable name of the
> controller
> > +  that is being managed by an EFI Driver.
> > +
> > +  @param[in]  This             A pointer to the
> > EFI_COMPONENT_NAME_PROTOCOL instance.
> > +  @param[in]  ControllerHandle The handle of a controller that the driver
> > specified by
> > +                               This is managing.  This handle
> > specifies the controller
> > +                               whose name is to be returned.
> > +  @param[in]  ChildHandle      The handle of the child controller to
> > retrieve the name
> > +                               of.  This is an optional parameter
> > that may be NULL.  It
> > +                               will be NULL for device drivers.  It
> > will also be NULL
> > +                               for a bus drivers that wish to retrieve
> > the name of the
> > +                               bus controller.  It will not be NULL
> > for a bus driver
> > +                               that wishes to retrieve the name of a
> > child controller.
> > +  @param[in]  Language         A pointer to a three character ISO
> > 639-2 language
> > +                               identifier.  This is the language of the
> > controller name
> > +                               that the caller is requesting, and it
> > must match one
> > +                               of the languages specified in
> > SupportedLanguages.  The
> > +                               number of languages supported by a
> > driver is up to the
> > +                              driver writer.
> > +  @param[out]  ControllerName  A pointer to the Unicode string to
> > return.  This Unicode
> > +                               string is the name of the controller
> > specified by
> > +                               ControllerHandle and ChildHandle in
> > the language specified
> > +                               by Language, from the point of view
> > of the driver specified
> > +                               by This.
> > +
> > +  @retval EFI_SUCCESS           The Unicode string for the
> > user-readable name in the
> > +                                language specified by Language for
> > the driver
> > +                                specified by This was returned in
> > DriverName.
> > +  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> > +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> > valid EFI_HANDLE.
> > +  @retval EFI_INVALID_PARAMETER Language is NULL.
> > +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> > +  @retval EFI_UNSUPPORTED       The driver specified by This is not
> > currently managing
> > +                                the controller specified by
> > ControllerHandle and
> > +                                ChildHandle.
> > +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> > support the
> > +                                language specified by Language.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishDiscoverComponentNameGetControllerName (
> > +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> > +  IN  EFI_HANDLE                    ControllerHandle,
> > +  IN  EFI_HANDLE                    ChildHandle
> > OPTIONAL,
> > +  IN  CHAR8                         *Language,
> > +  OUT CHAR16                        **ControllerName
> > +  )
> > +{
> > +  return EFI_UNSUPPORTED;
> > +}
> > diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
> > b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
> > new file mode 100644
> > index 0000000000..80d70a4679
> > --- /dev/null
> > +++ b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
> > @@ -0,0 +1,1910 @@
> > +/** @file
> > +
> > +  The implementation of EFI Redfidh Discover Protocol.
> > +
> > +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> > +
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include "RedfishDiscoverInternal.h"
> > +
> > +LIST_ENTRY mRedfishDiscoverList;
> > +LIST_ENTRY mRedfishInstanceList;
> > +EFI_SMBIOS_PROTOCOL *mSmbios = NULL;
> > +
> > +UINTN mNumNetworkInterface = 0;
> > +UINTN mNumRestExInstance = 0;
> > +LIST_ENTRY mEfiRedfishDiscoverNetworkInterface;
> > +LIST_ENTRY mEfiRedfishDiscoverRestExInstance;
> > +
> > +EFI_GUID mRedfishDiscoverTcp4InstanceGuid =
> > EFI_REDFISH_DISCOVER_TCP4_INSTANCE_GUID;
> > +EFI_GUID mRedfishDiscoverTcp6InstanceGuid =
> > EFI_REDFISH_DISCOVER_TCP6_INSTANCE_GUID;
> > +EFI_GUID mRedfishDiscoverRestExInstanceGuid =
> > EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_GUID;
> > +
> > +EFI_HANDLE EfiRedfishDiscoverProtocolHandle = NULL;
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +Tcp4GetSubnetInfo (
> > +  IN EFI_HANDLE ImageHandle,
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
> > +);
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +Tcp6GetSubnetInfo (
> > +  IN EFI_HANDLE ImageHandle,
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
> > +);
> > +
> > +static REDFISH_DISCOVER_REQUIRED_PROTOCOL gRequiredProtocol[] = {
> > +  {
> > +    ProtocolTypeTcp4,
> > +    L"TCP4 Service Binding Protocol",
> > +    &gEfiTcp4ProtocolGuid,
> > +    &gEfiTcp4ServiceBindingProtocolGuid,
> > +    &mRedfishDiscoverTcp4InstanceGuid,
> > +    Tcp4GetSubnetInfo
> > +  },
> > +  {
> > +    ProtocolTypeTcp6,
> > +    L"TCP6 Service Binding Protocol",
> > +    &gEfiTcp6ProtocolGuid,
> > +    &gEfiTcp6ServiceBindingProtocolGuid,
> > +    &mRedfishDiscoverTcp6InstanceGuid,
> > +    Tcp6GetSubnetInfo
> > +  },
> > +  {
> > +    ProtocolTypeRestEx,
> > +    L"REST EX Service Binding Protocol",
> > +    &gEfiRestExProtocolGuid,
> > +    &gEfiRestExServiceBindingProtocolGuid,
> > +    &mRedfishDiscoverRestExInstanceGuid,
> > +    NULL
> > +  }
> > +};
> > +
> > +/**
> > +  This function creates REST EX instance for the found Resfish service.
> > +  by known owner handle.
> > +
> > +  @param[in]    Instance
> > EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
> > +  @param[in]    Token           Client token.
> > +
> > +  @retval NULL  Instance not found.
> > +  @retval EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE The instance
> > owned by this owner.
> > +
> > +**/
> > +EFI_STATUS
> > +CreateRestExInstance (
> > +  IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
> > +  IN EFI_REDFISH_DISCOVERED_TOKEN *Token
> > +  )
> > +{
> > +  EFI_STATUS Status;
> > +
> > +  Status = RestExLibCreateChild (
> > +            Instance->Owner,
> > +            FixedPcdGetBool (PcdRedfishDiscoverAccessModeInBand)?
> > EfiRestExServiceInBandAccess: EfiRestExServiceOutOfBandAccess,
> > +            EfiRestExConfigHttp,
> > +            EfiRestExServiceRedfish,
> > +
> > &Token->DiscoverList.RedfishInstances-
> >Information.RedfishRestExHandle
> > +            );
> > +  return Status;
> > +}
> > +
> > +/**
> > +  This function gets EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
> > +  by known owner handle.
> > +
> > +  @param[in]    ImageHandle             Image handle owns
> > EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
> > +  @param[in]    TargetNetworkInterface  Target network interface used
> > by this EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
> > +  @param[in]    DiscoverFlags
> > EFI_REDFISH_DISCOVER_FLAG
> > +
> > +  @retval NULL  Instance not found.
> > +  @retval EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE The instance
> > owned by this owner.
> > +
> > +**/
> > +EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *
> > +GetInstanceByOwner (
> > +  IN EFI_HANDLE ImageHandle,
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *TargetNetworkInterface,
> > +  IN EFI_REDFISH_DISCOVER_FLAG DiscoverFlags
> > +  )
> > +{
> > +  EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *ThisInstance;
> > +
> > +  if (IsListEmpty (&mRedfishDiscoverList)) {
> > +    return NULL;
> > +  }
> > +  ThisInstance =
> > +    (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)GetFirstNode
> > (&mRedfishDiscoverList);
> > +  while (TRUE) {
> > +    if ((ThisInstance->Owner == ImageHandle) &&
> > +         (ThisInstance->DiscoverFlags == DiscoverFlags) &&
> > +         (ThisInstance->NetworkInterface == TargetNetworkInterface)) {
> > +      return ThisInstance;
> > +    }
> > +    if (IsNodeAtEnd (&mRedfishDiscoverList, &ThisInstance->Entry)) {
> > +      break;
> > +    }
> > +    ThisInstance =
> > +      (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)GetNextNode
> > (&mRedfishDiscoverList, &ThisInstance->Entry);
> > +  };
> > +  return NULL;
> > +}
> > +
> > +/**
> > +  This function gets the subnet information of this TCP4 instance.
> > +
> > +  @param[in]            ImageHandle  EFI handle with this image.
> > +  @param[in]            Instance  Instance of Network interface.
> > +  @retval EFI_STATUS    Get subnet information successfully.
> > +  @retval Otherwise     Fail to get subnet information.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +Tcp4GetSubnetInfo (
> > +  IN EFI_HANDLE ImageHandle,
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
> > +)
> > +{
> > +  EFI_STATUS Status;
> > +  EFI_TCP4_PROTOCOL *Tcp4;
> > +  EFI_TCP4_CONFIG_DATA Tcp4CfgData;
> > +  EFI_TCP4_OPTION Tcp4Option;
> > +  EFI_IP4_MODE_DATA IpModedata;
> > +  UINT8 SubnetMaskIndex;
> > +  UINT8 BitMask;
> > +  UINT8 PrefixLength;
> > +  BOOLEAN GotPrefixLength;
> > +
> > +  if (Instance == NULL) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +  Tcp4 = (EFI_TCP4_PROTOCOL
> > *)Instance->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
> > +
> > +  ZeroMem ((VOID *)&Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
> > +  ZeroMem ((VOID *)&Tcp4Option, sizeof (EFI_TCP4_OPTION));
> > +  // Give a local host IP address just for getting subnet information.
> > +  Tcp4CfgData.AccessPoint.UseDefaultAddress = TRUE;
> > +  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [0] = 127;
> > +  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [1] = 0;
> > +  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [2] = 0;
> > +  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [3] = 1;
> > +  Tcp4CfgData.AccessPoint.RemotePort  = 80;
> > +  Tcp4CfgData.AccessPoint.ActiveFlag  = TRUE;
> > +
> > +  Tcp4CfgData.ControlOption = &Tcp4Option;
> > +  Tcp4Option.ReceiveBufferSize      = 65535;
> > +  Tcp4Option.SendBufferSize         = 65535;
> > +  Tcp4Option.MaxSynBackLog          = 5;
> > +  Tcp4Option.ConnectionTimeout      = 60;
> > +  Tcp4Option.DataRetries            = 12;
> > +  Tcp4Option.FinTimeout             = 2;
> > +  Tcp4Option.KeepAliveProbes        = 6;
> > +  Tcp4Option.KeepAliveTime          = 7200;
> > +  Tcp4Option.KeepAliveInterval      = 30;
> > +  Tcp4Option.EnableNagle            = TRUE;
> > +  Status = Tcp4->Configure (Tcp4, &Tcp4CfgData);
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "%a: Can't get subnet information\n",
> > __FUNCTION__));
> > +    return Status;
> > +  }
> > +  Status = Tcp4->GetModeData (Tcp4, NULL, NULL, &IpModedata, NULL,
> > NULL);
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "%a: Can't get IP mode data information\n",
> > __FUNCTION__));
> > +    return Status;
> > +  }
> > +  IP4_COPY_ADDRESS (&Instance->SubnetMask,
> > &IpModedata.ConfigData.SubnetMask);
> > +  Instance->SubnetAddr.v4.Addr [0] =
> > IpModedata.ConfigData.StationAddress.Addr [0] &
> > Instance->SubnetMask.v4.Addr [0];
> > +  Instance->SubnetAddr.v4.Addr [1] =
> > IpModedata.ConfigData.StationAddress.Addr [1] &
> > Instance->SubnetMask.v4.Addr [1];
> > +  Instance->SubnetAddr.v4.Addr [2] =
> > IpModedata.ConfigData.StationAddress.Addr [2] &
> > Instance->SubnetMask.v4.Addr [2];
> > +  Instance->SubnetAddr.v4.Addr [3] =
> > IpModedata.ConfigData.StationAddress.Addr [3] &
> > Instance->SubnetMask.v4.Addr [3];
> > +  //
> > +  // Calculate the subnet mask prefix.
> > +  //
> > +  GotPrefixLength = FALSE;
> > +  PrefixLength = 0;
> > +  SubnetMaskIndex = 0;
> > +  while (GotPrefixLength == FALSE && SubnetMaskIndex < 4) {
> > +    BitMask = 0x80;
> > +    while (BitMask != 0) {
> > +      if ((Instance->SubnetMask.v4.Addr [SubnetMaskIndex] & BitMask) !=
> > 0) {
> > +        PrefixLength ++;
> > +      } else {
> > +        GotPrefixLength = TRUE;
> > +        break;
> > +      }
> > +      BitMask = BitMask >> 1;
> > +    };
> > +    SubnetMaskIndex ++;
> > +  };
> > +  Instance->SubnetPrefixLength = PrefixLength;
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This function gets the subnet information of this TCP6 instance.
> > +
> > +  @param[in]            ImageHandle  EFI handle with this image.
> > +  @param[in]            Instance  Instance of Network interface.
> > +  @retval EFI_STATUS    Get subnet information successfully.
> > +  @retval Otherwise     Fail to get subnet information.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +Tcp6GetSubnetInfo (
> > +  IN EFI_HANDLE ImageHandle,
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
> > +)
> > +{
> > +  EFI_STATUS Status;
> > +  EFI_TCP6_PROTOCOL *Tcp6;
> > +  EFI_IP6_MODE_DATA IpModedata;
> > +
> > +  if (Instance == NULL) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +  Tcp6 = (EFI_TCP6_PROTOCOL
> > *)Instance->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
> > +
> > +  Status = Tcp6->GetModeData (Tcp6, NULL, NULL, &IpModedata, NULL,
> > NULL);
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "%a: Can't get IP mode data information\n"));
> > +    return Status;
> > +  }
> > +  if (IpModedata.AddressCount == 0) {
> > +    DEBUG ((DEBUG_INFO, "%a: No IPv6 address configured.\n"));
> > +  }
> > +  if (Instance->SubnetAddrInfoIPv6 != NULL) {
> > +    FreePool (Instance->SubnetAddrInfoIPv6);
> > +  }
> > +  Instance->SubnetAddrInfoIPv6 = AllocateZeroPool
> > (IpModedata.AddressCount * sizeof (EFI_IP6_ADDRESS_INFO));
> > +  if (Instance->SubnetAddrInfoIPv6 == NULL) {
> > +    DEBUG ((DEBUG_ERROR, "%a: Failed to allocate memory fir IPv6
> > subnet address information\n"));
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +  Instance->SubnetAddrInfoIPv6Number = IpModedata.AddressCount;
> > +  CopyMem (
> > +    (VOID *)Instance->SubnetAddrInfoIPv6,
> > +    (VOID *)&IpModedata.AddressList,
> > +    IpModedata.AddressCount * sizeof (EFI_IP6_ADDRESS_INFO)
> > +    );
> > +  FreePool (IpModedata.AddressList);
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This function searches
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > +  instance with the given
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
> > +
> > +  @param[in] TargetNetworkInterface
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
> > +                                     NULL for all
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACEs.
> > +
> > +  @retval Non-NULL
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL is returned.
> > +  @retval NULL      Non of
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance is
> > returned.
> > +**/
> > +EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *
> > +GetTargetNetworkInterfaceInternal (
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE
> > *TargetNetworkInterface
> > +  )
> > +{
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *ThisNetworkInterface;
> > +
> > +  ThisNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetFirstNode
> > (&mEfiRedfishDiscoverNetworkInterface);
> > +  while (TRUE) {
> > +    if (CompareMem((VOID *)&ThisNetworkInterface->MacAddress,
> > &TargetNetworkInterface->MacAddress,
> > ThisNetworkInterface->HwAddressSize) == 0) {
> > +      return ThisNetworkInterface;
> > +    }
> > +    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface,
> > &ThisNetworkInterface->Entry)) {
> > +      return NULL;
> > +    }
> > +    ThisNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> > &ThisNetworkInterface->Entry);
> > +  };
> > +  return NULL;
> > +}
> > +
> > +/**
> > +  This function validate if target network interface is ready for
> discovering
> > +  Redfish service.
> > +
> > +  @param[in] TargetNetworkInterface
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
> > +                                     NULL for all
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACEs.
> > +  @param[in] Flags                   EFI_REDFISH_DISCOVER_FLAG
> > +
> > +  @retval EFI_SUCCESS     Target network interface is ready to use.
> > +  @retval EFI_UNSUPPORTED Target network interface is not ready to use.
> > +**/
> > +EFI_STATUS
> > +ValidateTargetNetworkInterface (
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE
> > *TargetNetworkInterface,
> > +  IN EFI_REDFISH_DISCOVER_FLAG Flags
> > +  )
> > +{
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *ThisNetworkInterface;
> > +
> > +  if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface) &&
> > TargetNetworkInterface == NULL) {
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +  if (TargetNetworkInterface == NULL) {
> > +    return EFI_SUCCESS; // Return EFI_SUCCESS if no network interface is
> > specified.
> > +  }
> > +
> > +  ThisNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *)GetFirstNode(&mEfiRedfishDiscoverNetworkInterface);
> > +  while (TRUE) {
> > +    if (CompareMem((VOID *)&ThisNetworkInterface->MacAddress,
> > &TargetNetworkInterface->MacAddress,
> > ThisNetworkInterface->HwAddressSize) == 0) {
> > +      break;
> > +    }
> > +    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface,
> > &ThisNetworkInterface->Entry)) {
> > +      return EFI_UNSUPPORTED;
> > +    }
> > +    ThisNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> > &ThisNetworkInterface->Entry);
> > +  };
> > +  if ((Flags & EFI_REDFISH_DISCOVER_SSDP) != 0) {
> > +    // Validate if UDP4/6 is supported on the given network interface.
> > +    // SSDP is not supported.
> > +
> > +    return EFI_SUCCESS;
> > +  }
> > +  if
> > (ThisNetworkInterface-
> >NetworkInterfaceProtocolInfo.ProtocolControllerHan
> > dle == NULL) {
> > +    return EFI_UNSUPPORTED; // The required protocol on this network
> > interface is not found.
> > +  }
> > +  return EFI_SUCCESS;
> > +}
> > +/**
> > +  This function returns number of network interface instance.
> > +
> > +  @retval UINTN  Number of network interface instances.
> > +**/
> > +UINTN
> > +NumberOfNetworkInterface (VOID)
> > +{
> > +  UINTN Num;
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *ThisNetworkInterface;
> > +
> > +  if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
> > +    return 0;
> > +  }
> > +
> > +  Num = 1;
> > +  ThisNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetFirstNode
> > (&mEfiRedfishDiscoverNetworkInterface);
> > +  while (TRUE) {
> > +    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface,
> > &ThisNetworkInterface->Entry)) {
> > +      break;
> > +    }
> > +    ThisNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> > &ThisNetworkInterface->Entry);
> > +    Num ++;
> > +  };
> > +  return Num;
> > +}
> > +
> > +/**
> > +  This function checks the  IP version supported on this
> > +  netwoek interface.
> > +
> > +  @param[in]    ThisNetworkInterface
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > +
> > +  @retval TRUE  Is IPv6, otherwise IPv4.
> > +
> > +**/
> > +BOOLEAN
> > +CheckIsIpVersion6 (
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *ThisNetworkInterface
> > +)
> > +{
> > +  if (ThisNetworkInterface->NetworkProtocolType == ProtocolTypeTcp6) {
> > +    return TRUE;
> > +  }
> > +  return FALSE;
> > +}
> > +
> > +/**
> > +  This function discover Redfish service through SMBIOS host interface.
> > +
> > +  @param[in]    Instance
> > EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
> > +
> > +  @retval EFI_SUCCESS        Redfish service is discovered through
> > SMBIOS Host interface.
> > +  @retval Others             Fail to discover Redfish service throught
> > SMBIOS host interface
> > +
> > +**/
> > +EFI_STATUS
> > +DiscoverRedfishHostInterface (IN
> > EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance)
> > +{
> > +  EFI_STATUS Status;
> > +  REDFISH_OVER_IP_PROTOCOL_DATA *Data;
> > +  REDFISH_INTERFACE_DATA  *DeviceDescriptor;
> > +  CHAR8 UuidStr[sizeof"00000000-0000-0000-0000-000000000000" + 1];
> > +  CHAR16 Ipv6Str [sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1];
> > +  CHAR8 RedfishServiceLocateStr
> [sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1];
> > +  UINTN StrSize;
> > +  UINTN MacCompareStstus;
> > +  BOOLEAN IsHttps;
> > +
> > +  Data = NULL;
> > +  DeviceDescriptor = NULL;
> > +
> > +  if (mSmbios == NULL) {
> > +    Status = gBS->LocateProtocol(&gEfiSmbiosProtocolGuid, NULL, (VOID
> > **)&mSmbios);
> > +    if (EFI_ERROR (Status)) {
> > +      return Status;
> > +    }
> > +  }
> > +  Status = RedfishGetHostInterfaceProtocolData (mSmbios,
> > &DeviceDescriptor, &Data); // Search for SMBIOS type 42h
> > +  if (!EFI_ERROR (Status) && Data != NULL && DeviceDescriptor != NULL) {
> > +    //
> > +    // Chceck if we can reach out Redfish service using this network
> > interface.
> > +    // Check with MAC address using Device Descroptor Data Device Type
> > 04 and Type 05.
> > +    // Those two types of Redfish host interface device has MAC
> > information.
> > +    //
> > +    if (DeviceDescriptor->DeviceType ==
> > REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2) {
> > +      MacCompareStstus =
> > CompareMem(&Instance->NetworkInterface->MacAddress,
> > &DeviceDescriptor->DeviceDescriptor.PciPcieDeviceV2.MacAddress, 6);
> > +    } else if (DeviceDescriptor->DeviceType ==
> > REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2){
> > +      MacCompareStstus =
> > CompareMem(&Instance->NetworkInterface->MacAddress,
> > &DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.MacAddress, 6);
> > +    } else {
> > +      return EFI_UNSUPPORTED;
> > +    }
> > +    if (MacCompareStstus != 0) {
> > +      return EFI_UNSUPPORTED;
> > +    }
> > +
> > +    if (Data->RedfishServiceIpAddressFormat == 1) {
> > +      IP4_COPY_ADDRESS ((VOID *)&Instance->TargetIpAddress.v4, (VOID
> > *)Data->RedfishServiceIpAddress);
> > +    } else {
> > +      IP6_COPY_ADDRESS ((VOID *)&Instance->TargetIpAddress.v6, (VOID
> > *)Data->RedfishServiceIpAddress);
> > +    }
> > +
> > +    if (Instance->HostIntfValidation) {
> > +      DEBUG ((DEBUG_ERROR,"%a:Send UPnP unicast SSDP to validate
> > this Redfish Host Interface is not supported.\n", __FUNCTION__));
> > +      Status = EFI_UNSUPPORTED;
> > +    } else {
> > +      //
> > +      // Add this istance to list without detial information of Redfish
> > +      // service.
> > +      //
> > +      IsHttps = FALSE;
> > +      if (Data->RedfishServiceIpPort == 443) {
> > +        IsHttps = TRUE;
> > +      }
> > +      StrSize = sizeof(UuidStr);
> > +      AsciiSPrint(UuidStr, StrSize, "%g", &Data->ServiceUuid);
> > +      //
> > +      // Generate Redfish service location string.
> > +      //
> > +      if (Data->RedfishServiceIpAddressFormat ==
> > REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP6) {
> > +        NetLibIp6ToStr((IPv6_ADDRESS *)&Data->RedfishServiceIpAddress,
> > Ipv6Str, sizeof (Ipv6Str));
> > +        if (Data->RedfishServiceIpPort == 0 || IsHttps == TRUE) {
> > +            AsciiSPrintUnicodeFormat (
> > +              RedfishServiceLocateStr,
> > +              sizeof (RedfishServiceLocateStr),
> > +              L"%s",
> > +              Ipv6Str
> > +            );
> > +        } else {
> > +            AsciiSPrintUnicodeFormat(
> > +              RedfishServiceLocateStr,
> > +              sizeof (RedfishServiceLocateStr),
> > +              L"[%s]:%d",
> > +              Ipv6Str,
> > +              Data->RedfishServiceIpPort
> > +            );
> > +        }
> > +      } else {
> > +        if (Data->RedfishServiceIpPort == 0 || IsHttps == TRUE) {
> > +          AsciiSPrint(
> > +            RedfishServiceLocateStr,
> > +            sizeof (RedfishServiceLocateStr),
> > +            "%d.%d.%d.%d",
> > +            Data->RedfishServiceIpAddress [0],
> > +            Data->RedfishServiceIpAddress [1],
> > +            Data->RedfishServiceIpAddress [2],
> > +            Data->RedfishServiceIpAddress [3]
> > +            );
> > +        } else {
> > +          AsciiSPrint(
> > +            RedfishServiceLocateStr,
> > +            sizeof (RedfishServiceLocateStr),
> > +            "%d.%d.%d.%d:%d",
> > +            Data->RedfishServiceIpAddress [0],
> > +            Data->RedfishServiceIpAddress [1],
> > +            Data->RedfishServiceIpAddress [2],
> > +            Data->RedfishServiceIpAddress [3],
> > +            Data->RedfishServiceIpPort
> > +            );
> > +        }
> > +       }
> > +      Status = AddAndSignalNewRedfishService (
> > +            Instance,
> > +            NULL,
> > +            RedfishServiceLocateStr,
> > +            UuidStr,
> > +            NULL,
> > +            NULL,
> > +            NULL,
> > +            NULL,
> > +            IsHttps
> > +            );
> > +    }
> > +  }
> > +  return Status;
> > +}
> > +
> > +/**
> > +  The function adds a new found Redfish service to internal list and
> > +  notify client.
> > +
> > +  @param[in]  Instance
> > EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
> > +  @param[in]  RedfishVersion        Redfish version.
> > +  @param[in]  RedfishLocation       Redfish location.
> > +  @param[in]  Uuid                  Service UUID string.
> > +  @param[in]  Os                    OS string.
> > +  @param[in]  OsVer                 OS version string.
> > +  @param[in]  Product               Product string.
> > +  @param[in]  ProductVer            Product verison string.
> > +  @param[in]  UseHttps              Redfish service requires secured
> > connection.
> > +  @retval EFI_SUCCESS               Redfish service is added to list
> > successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +AddAndSignalNewRedfishService (
> > +  IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
> > +  IN UINTN *RedfishVersion OPTIONAL,
> > +  IN CHAR8 *RedfishLocation OPTIONAL,
> > +  IN CHAR8 *Uuid  OPTIONAL,
> > +  IN CHAR8 *Os  OPTIONAL,
> > +  IN CHAR8 *OsVer  OPTIONAL,
> > +  IN CHAR8 *Product  OPTIONAL,
> > +  IN CHAR8 *ProductVer  OPTIONAL,
> > +  IN BOOLEAN UseHttps
> > +  )
> > +{
> > +  BOOLEAN NewFound;
> > +  BOOLEAN InfoRefresh;
> > +  BOOLEAN RestExOpened;
> > +  BOOLEAN DeleteRestEx;
> > +  EFI_STATUS Status;
> > +  EFI_REDFISH_DISCOVERED_INTERNAL_LIST *DiscoveredList;
> > +  EFI_REDFISH_DISCOVERED_INSTANCE *DiscoveredInstance;
> > +  CHAR16 *Char16Uuid;
> > +  EFI_REST_EX_PROTOCOL *RestEx;
> > +  EFI_REST_EX_HTTP_CONFIG_DATA *RestExHttpConfigData;
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *NetworkInterface;
> > +
> > +  NewFound = TRUE;
> > +  InfoRefresh = FALSE;
> > +  Char16Uuid = NULL;
> > +  RestExOpened = FALSE;
> > +  DeleteRestEx = FALSE;
> > +
> > +  DEBUG ((DEBUG_INFO,"%a:Add this instance to Redfish instance list.\n",
> > __FUNCTION__));
> > +
> > +  if (Uuid != NULL) {
> > +    Char16Uuid = (CHAR16 *)AllocateZeroPool(AsciiStrSize((const CHAR8
> > *)Uuid) * sizeof(CHAR16));
> > +    AsciiStrToUnicodeStrS ((const CHAR8 *)Uuid, Char16Uuid,
> > AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
> > +  }
> > +  DiscoveredList = NULL;
> > +  DiscoveredInstance = NULL;
> > +  RestExHttpConfigData = NULL;
> > +
> > +  NetworkInterface = Instance->NetworkInterface;
> > +  if (!IsListEmpty (&mRedfishInstanceList)) {
> > +    //
> > +    // Is this a duplicate redfish service.
> > +    //
> > +    DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST
> > *)GetFirstNode (&mRedfishInstanceList);
> > +    NewFound = FALSE;
> > +    do {
> > +      if (Char16Uuid == NULL ||
> > DiscoveredList->Instance->Information.Uuid == NULL) {
> > +        //
> > +        // Check if this Redfish instance already found using IP
> addrress.
> > +        //
> > +        if (!CheckIsIpVersion6(NetworkInterface)) {
> > +          if (CompareMem ((VOID *)&Instance->TargetIpAddress.v4,
> > +                      (VOID
> > *)&DiscoveredList->Instance->Information.RedfishHostIpAddress.v4,
> > +                      sizeof (EFI_IPv4_ADDRESS)
> > +                      ) == 0)
> > +          {
> > +            DiscoveredInstance = DiscoveredList->Instance;
> > +            if (DiscoveredList->Instance->Information.Uuid == NULL &&
> > +                Char16Uuid != NULL) {
> > +              InfoRefresh = TRUE;
> > +              DiscoveredInstance = DiscoveredList->Instance;
> > +              DEBUG((DEBUG_INFO,"*** This Redfish Service
> > information refresh ***\n"));
> > +            }
> > +            break;
> > +          }
> > +        } else {
> > +          if (CompareMem ((VOID *)&Instance->TargetIpAddress.v6,
> > +                      (VOID
> > *)&DiscoveredList->Instance->Information.RedfishHostIpAddress.v6,
> > +                      sizeof (EFI_IPv6_ADDRESS)
> > +                      ) == 0)
> > +          {
> > +            DiscoveredInstance = DiscoveredList->Instance;
> > +            break;
> > +          }
> > +        }
> > +      } else {
> > +        //
> > +        // Check if this Redfish instance already found using UUID.
> > +        //
> > +        if (StrCmp((const CHAR16 *)Char16Uuid, (const CHAR16
> > *)DiscoveredList->Instance->Information.Uuid) == 0) {
> > +          DiscoveredInstance = DiscoveredList->Instance;
> > +          break;
> > +        }
> > +      }
> > +      if (IsNodeAtEnd (&mRedfishInstanceList,
> > &DiscoveredList->NextInstance)) {
> > +        NewFound = TRUE;
> > +        break;
> > +      }
> > +      DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST
> > *)GetNextNode (&mRedfishInstanceList, &DiscoveredList->NextInstance);
> > +    } while (TRUE);
> > +  }
> > +  if (NewFound || InfoRefresh) {
> > +    if (!InfoRefresh) {
> > +      DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST
> > *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INTERNAL_LIST));
> > +      if (DiscoveredList == NULL) {
> > +        return EFI_OUT_OF_RESOURCES;
> > +      }
> > +      InitializeListHead (&DiscoveredList->NextInstance);
> > +      DiscoveredInstance = (EFI_REDFISH_DISCOVERED_INSTANCE
> > *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INSTANCE));
> > +      if (DiscoveredInstance == NULL) {
> > +        FreePool ((VOID *)DiscoveredList);
> > +        return EFI_OUT_OF_RESOURCES;
> > +      }
> > +    }
> > +    DEBUG ((DEBUG_INFO,"*** Redfish Service Information ***\n"));
> > +
> > +    DiscoveredInstance->Information.UseHttps = UseHttps;
> > +    if (RedfishVersion != NULL) {
> > +      DiscoveredInstance->Information.RedfishVersion = *RedfishVersion;
> > +      DEBUG ((DEBUG_INFO,"Redfish service version: %d.\n",
> > DiscoveredInstance->Information.RedfishVersion));
> > +    }
> > +    if (RedfishLocation != NULL) {
> > +      DiscoveredInstance->Information.Location = (CHAR16
> > *)AllocatePool(AsciiStrSize((const CHAR8 *)RedfishLocation) *
> > sizeof(CHAR16));
> > +      AsciiStrToUnicodeStrS ((const CHAR8 *)RedfishLocation,
> > DiscoveredInstance->Information.Location, AsciiStrSize((const CHAR8
> > *)RedfishLocation) * sizeof(CHAR16));
> > +      DEBUG ((DEBUG_INFO,"Redfish service location: %s.\n",
> > DiscoveredInstance->Information.Location));
> > +    }
> > +    if (Uuid != NULL) {
> > +      DiscoveredInstance->Information.Uuid = (CHAR16
> > *)AllocatePool(AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
> > +      AsciiStrToUnicodeStrS ((const CHAR8 *)Uuid,
> > DiscoveredInstance->Information.Uuid, AsciiStrSize((const CHAR8 *)Uuid)
> *
> > sizeof(CHAR16));
> > +      DEBUG ((DEBUG_INFO,"Service UUID: %s.\n",
> > DiscoveredInstance->Information.Uuid));
> > +    }
> > +    if (Os != NULL) {
> > +      DiscoveredInstance->Information.Os = (CHAR16
> > *)AllocatePool(AsciiStrSize((const CHAR8 *)Os) * sizeof(CHAR16));
> > +      AsciiStrToUnicodeStrS ((const CHAR8 *)Os,
> > DiscoveredInstance->Information.Os, AsciiStrSize((const CHAR8 *)Os) *
> > sizeof(CHAR16));
> > +      DEBUG ((DEBUG_INFO,"Redfish service OS: %s, Version:%s.\n",
> > DiscoveredInstance->Information.Os,
> > DiscoveredInstance->Information.OsVersion));
> > +    }
> > +    if (OsVer != NULL) {
> > +      DiscoveredInstance->Information.OsVersion = (CHAR16
> > *)AllocatePool(AsciiStrSize((const CHAR8 *)OsVer) * sizeof(CHAR16));
> > +      AsciiStrToUnicodeStrS ((const CHAR8 *)OsVer,
> > DiscoveredInstance->Information.OsVersion, AsciiStrSize((const CHAR8
> > *)OsVer) * sizeof(CHAR16));
> > +    }
> > +    if (Product != NULL && ProductVer != NULL) {
> > +      DiscoveredInstance->Information.Product = (CHAR16
> > *)AllocatePool(AsciiStrSize((const CHAR8 *)Product) * sizeof(CHAR16));
> > +      AsciiStrToUnicodeStrS ((const CHAR8 *)Product,
> > DiscoveredInstance->Information.Product, AsciiStrSize((const CHAR8
> > *)Product) * sizeof(CHAR16));
> > +      DiscoveredInstance->Information.ProductVer = (CHAR16
> > *)AllocatePool(AsciiStrSize((const CHAR8 *)ProductVer) * sizeof(CHAR16));
> > +      AsciiStrToUnicodeStrS ((const CHAR8 *)ProductVer,
> > DiscoveredInstance->Information.ProductVer, AsciiStrSize((const CHAR8
> > *)ProductVer) * sizeof(CHAR16));
> > +      DEBUG ((DEBUG_INFO,"Redfish service product: %s, Version:%s.\n",
> > DiscoveredInstance->Information.Product,
> > DiscoveredInstance->Information.ProductVer));
> > +    }
> > +
> > +    if (RedfishLocation == NULL) {
> > +      // This is the Redfish reported from SMBIOS 42h
> > +      // without validation.
> > +
> > +      IP4_COPY_ADDRESS((VOID
> > *)&DiscoveredInstance->Information.RedfishHostIpAddress.v4, (VOID
> > *)&Instance->TargetIpAddress.v4);
> > +    }
> > +    if (!InfoRefresh) {
> > +      DiscoveredList->Instance = DiscoveredInstance;
> > +      InsertTailList(&mRedfishInstanceList,
> > &DiscoveredList->NextInstance);
> > +    }
> > +    DiscoveredInstance->Status = EFI_SUCCESS;
> > +  } else {
> > +    if (DiscoveredList != NULL) {
> > +      DEBUG((DEBUG_INFO,"*** This Redfish Service was already found
> > ***\n"));
> > +      if (DiscoveredInstance->Information.Uuid != NULL) {
> > +        DEBUG((DEBUG_INFO,"Service UUID: %s.\n",
> > DiscoveredInstance->Information.Uuid));
> > +      } else {
> > +        DEBUG((DEBUG_INFO,"Service UUID: unknown.\n"));
> > +      }
> > +    }
> > +  }
> > +  if (Char16Uuid != NULL) {
> > +    FreePool((VOID *)Char16Uuid);
> > +  }
> > +
> > +  Status = EFI_SUCCESS;
> > +  if (NewFound || InfoRefresh) {
> > +    //
> > +    // Build up EFI_REDFISH_DISCOVERED_LIST in token.
> > +    //
> > +    Instance->DiscoverToken->DiscoverList.NumberOfServiceFound = 1;
> > +    Instance->DiscoverToken->DiscoverList.RedfishInstances =
> > DiscoveredInstance;
> > +    DiscoveredInstance->Status = EFI_SUCCESS;
> > +    if (!InfoRefresh) {
> > +      Status = CreateRestExInstance (Instance, Instance->DiscoverToken);
> > // Create REST EX child.
> > +      if (EFI_ERROR (Status)) {
> > +        DEBUG ((DEBUG_ERROR, "%a:Can't create REST EX child
> > instance.\n",__FUNCTION__));
> > +        goto ON_EXIT;
> > +      }
> > +      Status = gBS->OpenProtocol ( // Configure local host information.
> > +
> > Instance->DiscoverToken->DiscoverList.RedfishInstances-
> >Information.Redfis
> > hRestExHandle,
> > +                  &gEfiRestExProtocolGuid,
> > +                  (VOID **)&RestEx,
> > +
> > Instance->NetworkInterface->OpenDriverAgentHandle,
> > +
> > Instance->NetworkInterface->OpenDriverControllerHandle,
> > +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> > +                  );
> > +      if (EFI_ERROR (Status)) {
> > +        DeleteRestEx = TRUE;
> > +        goto ERROR_EXIT;
> > +      }
> > +      RestExOpened = TRUE;
> > +      RestExHttpConfigData = AllocateZeroPool (sizeof
> > (EFI_REST_EX_HTTP_CONFIG_DATA));
> > +      if (RestExHttpConfigData == NULL) {
> > +        Status = EFI_OUT_OF_RESOURCES;
> > +        DeleteRestEx = TRUE;
> > +        goto EXIT_FREE_CONFIG_DATA;
> > +      }
> > +      RestExHttpConfigData->SendReceiveTimeout = 5000;
> > +      RestExHttpConfigData->HttpConfigData.HttpVersion =
> > HttpVersion11;
> > +      RestExHttpConfigData->HttpConfigData.LocalAddressIsIPv6 =
> > CheckIsIpVersion6(NetworkInterface);
> > +      if (RestExHttpConfigData->HttpConfigData.LocalAddressIsIPv6) {
> > +        RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node =
> > AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT));
> > +        if (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node
> > == NULL) {
> > +          Status = EFI_OUT_OF_RESOURCES;
> > +          goto EXIT_FREE_CONFIG_DATA;
> > +        }
> > +      } else {
> > +        RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node =
> > AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT));
> > +        if (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node
> > == NULL) {
> > +          Status = EFI_OUT_OF_RESOURCES;
> > +          goto EXIT_FREE_CONFIG_DATA;
> > +        }
> > +
> > RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node-
> >UseDefaultA
> > ddress = TRUE;
> > +      }
> > +      Status = RestEx->Configure (
> > +                       RestEx,
> > +                       (EFI_REST_EX_CONFIG_DATA)(UINT8
> > *)RestExHttpConfigData
> > +                       );
> > +      if (EFI_ERROR (Status)) {
> > +        DEBUG ((DEBUG_ERROR,"%a:REST EX configured..\n",
> > __FUNCTION__));
> > +        DeleteRestEx = TRUE;
> > +        goto EXIT_FREE_ALL;
> > +      }
> > +      //
> > +      // Signal client, close REST EX before signaling client.
> > +      //
> > +      if (RestExOpened) {
> > +        gBS->CloseProtocol(
> > +
> > Instance->DiscoverToken->DiscoverList.RedfishInstances-
> >Information.Redfis
> > hRestExHandle,
> > +             &gEfiRestExProtocolGuid,
> > +             Instance->NetworkInterface->OpenDriverAgentHandle,
> > +             Instance->NetworkInterface->OpenDriverControllerHandle
> > +          );
> > +        RestExOpened = FALSE;
> > +      }
> > +    }
> > +    Status = gBS->SignalEvent(Instance->DiscoverToken->Event);
> > +    if (!EFI_ERROR (Status)) {
> > +      DEBUG ((DEBUG_ERROR,"%a:No event to signal!\n",
> > __FUNCTION__));
> > +    }
> > +  }
> > +
> > +EXIT_FREE_ALL:;
> > +  if (RestExHttpConfigData != NULL &&
> > RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node != NULL) {
> > +    FreePool
> > (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node);
> > +  }
> > +
> > +EXIT_FREE_CONFIG_DATA:;
> > +  if (RestExHttpConfigData != NULL) {
> > +    FreePool((VOID *)RestExHttpConfigData);
> > +  }
> > +  if (RestExOpened) {
> > +    gBS->CloseProtocol(
> > +
> > Instance->DiscoverToken->DiscoverList.RedfishInstances-
> >Information.Redfis
> > hRestExHandle,
> > +           &gEfiRestExProtocolGuid,
> > +           Instance->NetworkInterface->OpenDriverAgentHandle,
> > +           Instance->NetworkInterface->OpenDriverControllerHandle
> > +        );
> > +  }
> > +ERROR_EXIT:;
> > +    if (DeleteRestEx && RestExOpened) {
> > +      gBS->CloseProtocol(
> > +
> > Instance->DiscoverToken->DiscoverList.RedfishInstances-
> >Information.Redfis
> > hRestExHandle,
> > +           &gEfiRestExProtocolGuid,
> > +           Instance->NetworkInterface->OpenDriverAgentHandle,
> > +           Instance->NetworkInterface->OpenDriverControllerHandle
> > +        );
> > +    }
> > +ON_EXIT:;
> > +  return Status;
> > +}
> > +
> > +/**
> > +  This function gets the subnet information of this network interface
> > instance.
> > +  can discover Redfish service on it.
> > +
> > +  @param[in]    Instance
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance.
> > +  @param[in]    ImageHandle  EFI Image handle request the network
> > interface list.
> > +
> > +  @retval EFI_SUCCESS
> > +
> > +**/
> > +EFI_STATUS
> > +NetworkInterfaceGetSubnetInfo (
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *Instance,
> > +  IN EFI_HANDLE ImageHandle
> > +  )
> > +{
> > +  EFI_STATUS Status;
> > +  UINT32 ProtocolType;
> > +  UINT32 IPv6InfoIndex;
> > +  EFI_IP6_ADDRESS_INFO *ThisSubnetAddrInfoIPv6;
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *NewNetworkInterface;
> > +
> > +  if (Instance->GotSubnetInfo) {
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  ProtocolType = Instance->NetworkProtocolType;
> > +  if (gRequiredProtocol [ProtocolType].GetSubnetInfo != NULL &&
> > Instance->GotSubnetInfo == FALSE) {
> > +    Status = gRequiredProtocol [ProtocolType].GetSubnetInfo (
> > +        ImageHandle,
> > +        Instance
> > +        );
> > +    if (EFI_ERROR (Status)) {
> > +      DEBUG ((DEBUG_ERROR,"%a:Faile to get Subnet infomation.\n",
> > __FUNCTION__));
> > +      return Status;
> > +    } else {
> > +      DEBUG ((DEBUG_INFO,"%a:MAC address: %s\n", __FUNCTION__,
> > Instance->StrMacAddr));
> > +      if (CheckIsIpVersion6 (Instance)) {
> > +        if (Instance->SubnetAddrInfoIPv6Number == 0) {
> > +          DEBUG ((DEBUG_ERROR,"%a: There is no Subnet infomation for
> > IPv6 network interface.\n", __FUNCTION__));
> > +          return EFI_NOT_FOUND;
> > +        }
> > +        ThisSubnetAddrInfoIPv6 = Instance->SubnetAddrInfoIPv6; // First
> > IPv6 address information.
> > +        IP6_COPY_ADDRESS (&Instance->SubnetAddr.v6,
> > &ThisSubnetAddrInfoIPv6->Address);
> > +        Instance->SubnetPrefixLength =
> > ThisSubnetAddrInfoIPv6->PrefixLength;
> > +        DEBUG((DEBUG_INFO,"   IPv6 Subnet ID:%d, Prefix
> > length: %d.\n",
> > +               ThisSubnetAddrInfoIPv6->Address.Addr [7] +
> > (UINT16)ThisSubnetAddrInfoIPv6->Address.Addr [6] * 256,
> > +               ThisSubnetAddrInfoIPv6->PrefixLength)
> > +               );
> > +        //
> > +        // If this is IPv6, then we may have to propagate network
> interface
> > for IPv6 network scopes
> > +        // according to the Ipv6 address information.
> > +        //
> > +        ThisSubnetAddrInfoIPv6 ++;
> > +        for (IPv6InfoIndex = 0; IPv6InfoIndex <
> > Instance->SubnetAddrInfoIPv6Number - 1; IPv6InfoIndex++) {
> > +          //
> > +          // Build up addtional
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instances.
> > +          //
> > +          NewNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *)AllocateZeroPool (sizeof
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL));
> > +          if (NewNetworkInterface != NULL) {
> > +            CopyMem ((VOID *)NewNetworkInterface, (VOID *)Instance,
> > sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL)); //
> > Clone information of first instance.
> > +            IP6_COPY_ADDRESS
> > (&NewNetworkInterface->SubnetAddr.v6,
> > &ThisSubnetAddrInfoIPv6->Address);
> > +            NewNetworkInterface->SubnetPrefixLength =
> > ThisSubnetAddrInfoIPv6->PrefixLength;
> > +            NewNetworkInterface->GotSubnetInfo = TRUE;
> > +            InsertTailList (&mEfiRedfishDiscoverNetworkInterface,
> > &NewNetworkInterface->Entry);
> > +            ThisSubnetAddrInfoIPv6 ++;
> > +            mNumNetworkInterface ++;
> > +            DEBUG((DEBUG_INFO,"   IPv6 Subnet ID:%d, Prefix
> > length: %d.\n",
> > +                   ThisSubnetAddrInfoIPv6->Address.Addr [7] +
> > (UINT16)ThisSubnetAddrInfoIPv6->Address.Addr [6] * 256,
> > +                   ThisSubnetAddrInfoIPv6->PrefixLength)
> > +                  );
> > +          } else {
> > +            return EFI_OUT_OF_RESOURCES;
> > +          }
> > +        }
> > +      } else {
> > +        DEBUG ((DEBUG_INFO,"   IPv4 Subnet:%d.%d.%d.%d Subnet
> > mask: %d.%d.%d.%d.\n",
> > +                    Instance->SubnetAddr.v4.Addr [0],
> > +                    Instance->SubnetAddr.v4.Addr [1],
> > +                    Instance->SubnetAddr.v4.Addr [2],
> > +                    Instance->SubnetAddr.v4.Addr [3],
> > +                    Instance->SubnetMask.v4.Addr [0],
> > +                    Instance->SubnetMask.v4.Addr [1],
> > +                    Instance->SubnetMask.v4.Addr [2],
> > +                    Instance->SubnetMask.v4.Addr [3]
> > +                    ));
> > +      }
> > +    }
> > +  }
> > +  Instance->GotSubnetInfo = TRUE; // Only try to get Subnet Info once.
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This function gets the network interface list which Redfish discover
> > protocol
> > +  can discover Redfish service on it.
> > +
> > +  @param[in]    This
> > EFI_REDFISH_DISCOVER_PROTOCOL instance.
> > +  @param[in]    ImageHandle           EFI Image handle request the
> > network interface list,
> > +  @param[out]   NumberOfNetworkIntfs  Number of network interfaces
> > can do Redfish service discovery.
> > +  @param[out]   NetworkIntfInstances  Network interface instances.
> > It's an array of instance. The number of entries
> > +                                      in array is indicated by
> > NumberOfNetworkIntfs.
> > +                                      Caller has to release the
> > memory
> > +                                      allocated by Redfish discover
> > protocol.
> > +
> > +  @retval EFI_SUCCESS        The information of network interface is
> > returned in NumberOfNetworkIntfs and
> > +                             NetworkIntfInstances.
> > +  @retval Others             Fail to return the information of network
> > interface.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishServiceGetNetworkInterface (
> > +  IN EFI_REDFISH_DISCOVER_PROTOCOL   *This,
> > +  IN EFI_HANDLE                      ImageHandle,
> > +  OUT UINTN                          *NumberOfNetworkIntfs,
> > +  OUT EFI_REDFISH_DISCOVER_NETWORK_INTERFACE
> > **NetworkIntfInstances
> > +)
> > +{
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *ThisNetworkInterfaceIntn;
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *ThisNetworkInterface;
> > +
> > +  if (NetworkIntfInstances == NULL || NumberOfNetworkIntfs == NULL ||
> > ImageHandle == NULL) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  *NumberOfNetworkIntfs = 0;
> > +  *NetworkIntfInstances = NULL;
> > +
> > +  if (IsListEmpty ((const
> > LIST_ENTRY*)&mEfiRedfishDiscoverNetworkInterface)) {
> > +    return EFI_NOT_FOUND;
> > +  }
> > +
> > +  ThisNetworkInterface =
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE
> > *)AllocateZeroPool (sizeof
> (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE)
> > * mNumNetworkInterface);
> > +  if (ThisNetworkInterface == NULL) {
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +  *NetworkIntfInstances = ThisNetworkInterface;
> > +  ThisNetworkInterfaceIntn =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetFirstNode
> > (&mEfiRedfishDiscoverNetworkInterface);
> > +  while (TRUE) {
> > +    ThisNetworkInterface->IsIpv6 = FALSE;
> > +    if (CheckIsIpVersion6 (ThisNetworkInterfaceIntn)) {
> > +      ThisNetworkInterface->IsIpv6 = TRUE;
> > +    }
> > +    CopyMem((VOID *)&ThisNetworkInterface->MacAddress,
> > &ThisNetworkInterfaceIntn->MacAddress,
> > ThisNetworkInterfaceIntn->HwAddressSize);
> > +    NetworkInterfaceGetSubnetInfo(ThisNetworkInterfaceIntn,
> > ImageHandle); // Get subnet info.
> > +    if (!ThisNetworkInterface->IsIpv6) {
> > +      IP4_COPY_ADDRESS(&ThisNetworkInterface->SubnetId.v4,
> > &ThisNetworkInterfaceIntn->SubnetAddr.v4); // IPv4 subnet information.
> > +    } else {
> > +      IP6_COPY_ADDRESS (&ThisNetworkInterface->SubnetId.v6,
> > &ThisNetworkInterfaceIntn->SubnetAddr.v6); // IPv6 subnet information
> in
> > IPv6 address information.
> > +    }
> > +    ThisNetworkInterface->SubnetPrefixLength =
> > ThisNetworkInterfaceIntn->SubnetPrefixLength;
> > +    ThisNetworkInterface->VlanId = ThisNetworkInterfaceIntn->VlanId;
> > +    (*NumberOfNetworkIntfs) ++;
> > +    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface,
> > &ThisNetworkInterfaceIntn->Entry)) {
> > +      break;
> > +    }
> > +    ThisNetworkInterfaceIntn =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> > &ThisNetworkInterfaceIntn->Entry);
> > +    ThisNetworkInterface ++;
> > +  };
> > +  return EFI_SUCCESS;
> > +}
> > +/**
> > +  This function acquires Redfish services by discovering static Redfish
> setting
> > +  according to Redfish Host Interface or through SSDP. Returns a list of
> EFI
> > +  handles in EFI_REDFISH_DISCOVERED_LIST. Each of EFI handle has
> > cooresponding
> > +  EFI REST EX instance installed on it. Each REST EX isntance is a child
> > instance which
> > +  created through EFI REST EX serivce protoocl for communicating with
> > specific
> > +  Redfish service.
> > +
> > +  @param[in]    This
> > EFI_REDFISH_DISCOVER_PROTOCOL instance.
> > +  @param[in]    ImageHandle             EFI image owns these
> > Redfish service instances.
> > +  @param[in]    TargetNetworkInterface  Target network interface to
> > do the discovery.
> > +                                        NULL means discover
> > Redfish service on all network interfaces on platform.
> > +  @param[in]    Flags                   Redfish service discover
> > flags.
> > +  @param[in]    Token
> > EFI_REDFISH_DISCOVERED_TOKEN instance.
> > +                                        The memory of
> > EFI_REDFISH_DISCOVERED_LIST and the strings in
> > +
> > EFI_REDFISH_DISCOVERED_INFORMATION are all allocated by Acquire()
> > +                                        and must be freed when
> > caller invoke Release().
> > +
> > +  @retval EFI_SUCCESS             REST EX instance of discovered
> > Redfish services are returned.
> > +  @retval EFI_INVALID_PARAMETERS  ImageHandle == NULL, Flags == 0,
> > Token == NULL, Token->Timeout > 5,
> > +                                  or Token->Event == NULL.
> > +  @retval Others                  Fail acquire Redfish services.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishServiceAcquireService (
> > +  IN EFI_REDFISH_DISCOVER_PROTOCOL          *This,
> > +  IN EFI_HANDLE                             ImageHandle,
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE
> > *TargetNetworkInterface,
> > +  IN EFI_REDFISH_DISCOVER_FLAG              Flags,
> > +  IN EFI_REDFISH_DISCOVERED_TOKEN           *Token
> > +  )
> > +{
> > +  EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance;
> > +  EFI_STATUS Status1;
> > +  EFI_STATUS Status2;
> > +  BOOLEAN NewInstance;
> > +  UINTN NumNetworkInterfaces;
> > +  UINTN NetworkInterfacesIndex;
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *TargetNetworkInterfaceInternal;
> > +
> > +  DEBUG ((DEBUG_INFO,"%a:Entry.\n", __FUNCTION__));
> > +
> > +  //
> > +  // Validate parameters.
> > +  //
> > +  if (ImageHandle == NULL || Token == NULL || ((Flags &
> > ~EFI_REDFISH_DISCOVER_VALIDATION) == 0)) {
> > +    DEBUG ((DEBUG_ERROR,"%a:Invalid parameters.\n",
> > __FUNCTION__));
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +  //
> > +  // Validate target network interface.
> > +  //
> > +  if (EFI_ERROR (ValidateTargetNetworkInterface
> (TargetNetworkInterface,
> > Flags))) {
> > +      return EFI_UNSUPPORTED;
> > +  }
> > +  if (TargetNetworkInterface != NULL) {
> > +    TargetNetworkInterfaceInternal = GetTargetNetworkInterfaceInternal
> > (TargetNetworkInterface);
> > +    NumNetworkInterfaces = 1;
> > +  } else {
> > +    TargetNetworkInterfaceInternal =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetFirstNode
> > (&mEfiRedfishDiscoverNetworkInterface);
> > +    NumNetworkInterfaces = NumberOfNetworkInterface ();
> > +    if (NumNetworkInterfaces == 0) {
> > +      DEBUG ((DEBUG_ERROR,"%a:No network interface on platform.\n",
> > __FUNCTION__));
> > +      return EFI_UNSUPPORTED;
> > +    }
> > +  }
> > +  for (NetworkInterfacesIndex = 0; NetworkInterfacesIndex <
> > NumNetworkInterfaces; NetworkInterfacesIndex ++) {
> > +    Status1 = EFI_SUCCESS;
> > +    Status2 = EFI_SUCCESS;
> > +    NewInstance = FALSE;
> > +    Instance = GetInstanceByOwner (ImageHandle,
> > TargetNetworkInterfaceInternal, Flags &
> > ~EFI_REDFISH_DISCOVER_VALIDATION); // Check if we can re-use
> previous
> > instance.
> > +    if (Instance == NULL) {
> > +      DEBUG ((DEBUG_INFO,"%a:Create new
> > EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.\n", __FUNCTION__));
> > +      Instance = (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
> >
> *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE))
> > ;
> > +      if (Instance == NULL) {
> > +        DEBUG ((DEBUG_ERROR,"%a:Memory allocation fail.\n",
> > __FUNCTION__));
> > +      }
> > +      InitializeListHead (&Instance->Entry);
> > +      Instance->Owner = ImageHandle;
> > +      Instance->DiscoverFlags = Flags &
> > ~EFI_REDFISH_DISCOVER_VALIDATION;
> > +      Instance->NetworkInterface = TargetNetworkInterfaceInternal;
> > +      //
> > +      // Get subnet information in case subnet information is not set
> > because
> > +      // RedfishServiceGetNetworkInterfaces hasn't been called yet.
> > +      //
> > +      NetworkInterfaceGetSubnetInfo (TargetNetworkInterfaceInternal,
> > ImageHandle);
> > +      NewInstance = TRUE;
> > +    }
> > +    if (TargetNetworkInterfaceInternal->StrMacAddr != NULL) {
> > +      DEBUG((DEBUG_INFO,"%a:Acquire Redfish service on network
> > interface MAC address:%s.\n", __FUNCTION__,
> > TargetNetworkInterfaceInternal->StrMacAddr));
> > +    } else {
> > +      DEBUG((DEBUG_INFO,"%a:WARNING: No MAC address on this
> > network interface.\n", __FUNCTION__));
> > +    }
> > +
> > +    Instance->DiscoverToken = Token; // Always use the latest Token
> > passed by caller.
> > +    if ((Flags & EFI_REDFISH_DISCOVER_HOST_INTERFACE) != 0) {
> > +      DEBUG ((DEBUG_INFO,"%a:Redfish HOST interface discovery.\n",
> > __FUNCTION__));
> > +      Instance->HostIntfValidation = FALSE;
> > +      if ((Flags & EFI_REDFISH_DISCOVER_VALIDATION) != 0) {
> > +        Instance->HostIntfValidation = TRUE;
> > +      }
> > +      Status1 = DiscoverRedfishHostInterface (Instance); // Discover
> > Redfish service through Redfish Host Interface.
> > +    }
> > +    if ((Flags & EFI_REDFISH_DISCOVER_SSDP) != 0) {
> > +      DEBUG ((DEBUG_ERROR,"%a:Redfish service discovery through SSDP
> > is not supported\n", __FUNCTION__));
> > +      return EFI_UNSUPPORTED;
> > +    } else {
> > +      if (EFI_ERROR (Status1) && EFI_ERROR (Status2)) {
> > +        FreePool ((VOID *)Instance);
> > +        DEBUG ((DEBUG_ERROR,"%a:Something wrong on Redfish service
> > discovery Status1=%x, Status2=%x.\n", __FUNCTION__, Status1, Status2));
> > +      } else {
> > +        if (NewInstance) {
> > +          InsertTailList(&mRedfishDiscoverList, &Instance->Entry);
> > +        }
> > +      }
> > +    }
> > +    if (TargetNetworkInterface == NULL) {
> > +      //
> > +      // Discover Redfish services on all of network interfaces.
> > +      //
> > +      TargetNetworkInterfaceInternal =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> > &TargetNetworkInterfaceInternal->Entry);
> > +    }
> > +  }
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This function aborts Redfish service discovery on the given network
> > interface.
> > +
> > +  @param[in]    This
> > EFI_REDFISH_DISCOVER_PROTOCOL instance.
> > +  @param[in]    TargetNetworkInterface  Target network interface to
> > do the discovery.
> > +
> > +  @retval EFI_SUCCESS             REST EX instance of discovered
> > Redfish services are returned.
> > +  @retval Others                  Fail to abort Redfish service
> > discovery.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishServiceAbortAcquire (
> > +  IN EFI_REDFISH_DISCOVER_PROTOCOL      *This,
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE
> > *TargetNetworkInterface OPTIONAL
> > +)
> > +{
> > +  // This function is used to abort Redfish service discovery through
> SSDP
> > +  // on the network interface. SSDP is optionally supprted by
> > EFI_REDFISH_DISCOVER_PROTOCOL,
> > +  // we dont have implementation for SSDP now.
> > +
> > +  return EFI_UNSUPPORTED;
> > +}
> > +
> > +/**
> > +  This function releases Redfish services found by
> RedfishServiceAcquire().
> > +
> > +  @param[in]    This         EFI_REDFISH_DISCOVER_PROTOCOL
> > instance.
> > +  @param[in]    InstanceList The Redfish service to release.
> > +
> > +  @retval EFI_SUCCESS        REST EX instances of discovered Redfish
> > are released.
> > +  @retval Others             Fail to remove the entry
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishServiceReleaseService (
> > +  IN EFI_REDFISH_DISCOVER_PROTOCOL   *This,
> > +  IN EFI_REDFISH_DISCOVERED_LIST *InstanceList
> > +  )
> > +{
> > +  UINTN NumService;
> > +  BOOLEAN AnyFailRelease;
> > +  EFI_REDFISH_DISCOVERED_INSTANCE *ThisRedfishInstance;
> > +  EFI_REDFISH_DISCOVERED_INTERNAL_LIST *DiscoveredRedfishInstance;
> > +
> > +  if (IsListEmpty (&mRedfishInstanceList)) {
> > +    DEBUG ((DEBUG_ERROR,"%a:No any discovered Redfish service.\n",
> > __FUNCTION__));
> > +    return EFI_NOT_FOUND;
> > +  }
> > +  AnyFailRelease = FALSE;
> > +  ThisRedfishInstance = InstanceList->RedfishInstances;
> > +  for (NumService = 0; NumService < InstanceList-
> >NumberOfServiceFound;
> > NumService ++) {
> > +    DiscoveredRedfishInstance =
> > (EFI_REDFISH_DISCOVERED_INTERNAL_LIST
> > *)GetFirstNode(&mRedfishInstanceList);
> > +    do {
> > +      if (DiscoveredRedfishInstance->Instance == ThisRedfishInstance) {
> > +        RemoveEntryList (&DiscoveredRedfishInstance->NextInstance);
> > +        if (ThisRedfishInstance->Information.Location != NULL) {
> > +          FreePool (ThisRedfishInstance->Information.Location);
> > +        }
> > +        if (ThisRedfishInstance->Information.Uuid != NULL) {
> > +          FreePool (ThisRedfishInstance->Information.Uuid);
> > +        }
> > +        if (ThisRedfishInstance->Information.Os != NULL) {
> > +          FreePool (ThisRedfishInstance->Information.Os);
> > +        }
> > +        if (ThisRedfishInstance->Information.OsVersion != NULL) {
> > +          FreePool (ThisRedfishInstance->Information.OsVersion);
> > +        }
> > +        if (ThisRedfishInstance->Information.Product != NULL) {
> > +          FreePool (ThisRedfishInstance->Information.Product);
> > +        }
> > +        if (ThisRedfishInstance->Information.ProductVer != NULL) {
> > +          FreePool (ThisRedfishInstance->Information.ProductVer);
> > +        }
> > +        FreePool((VOID *)ThisRedfishInstance);
> > +        goto ReleaseNext;
> > +      }
> > +
> > +      if (IsNodeAtEnd(&mRedfishInstanceList,
> > &DiscoveredRedfishInstance->NextInstance)) {
> > +        break;
> > +      }
> > +      DiscoveredRedfishInstance =
> > (EFI_REDFISH_DISCOVERED_INTERNAL_LIST
> > *)GetNextNode(&mRedfishInstanceList,
> > &DiscoveredRedfishInstance->NextInstance);
> > +    } while (TRUE);
> > +    AnyFailRelease = TRUE;
> > +ReleaseNext:;
> > +    //
> > +    // Release next discovered Redfish Service.
> > +    //
> > +    ThisRedfishInstance = (EFI_REDFISH_DISCOVERED_INSTANCE
> > *)((UINT8 *)ThisRedfishInstance + sizeof
> > (EFI_REDFISH_DISCOVERED_INSTANCE));
> > +  }
> > +  if (AnyFailRelease) {
> > +    return EFI_NOT_FOUND;
> > +  } else {
> > +    return EFI_SUCCESS;
> > +  }
> > +}
> > +
> > +EFI_REDFISH_DISCOVER_PROTOCOL mRedfishDiscover = {
> > +  RedfishServiceGetNetworkInterface,
> > +  RedfishServiceAcquireService,
> > +  RedfishServiceAbortAcquire,
> > +  RedfishServiceReleaseService
> > +};
> > +
> > +/**
> > +  This function create an
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL for the
> > +  given network interface.
> > +
> > +
> > +  @param[in]  ControllerHandle    MAC address of this network
> > interface.
> > +  @param[in]  NetworkProtocolType Network protocol type.
> > +  @param[out] IsNewInstance       BOOLEAN means new instance or
> > not.
> > +  @param[out] NetworkInterface    Pointer to to
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL.
> > +
> > +  @retval EFI_STATUS
> > +**/
> > +EFI_STATUS
> > +CreateRedfishDiscoverNetworkInterface (
> > +  IN EFI_HANDLE ControllerHandle,
> > +  IN UINT32 NetworkProtocolType,
> > +  OUT BOOLEAN  *IsNewInstance,
> > +  OUT EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > **NetworkInterface
> > +  )
> > +{
> > +  EFI_MAC_ADDRESS MacAddress;
> > +  UINTN HwAddressSize;
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *ThisNetworkInterface;
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *NewNetworkInterface;
> > +
> > +  NetLibGetMacAddress (ControllerHandle, &MacAddress,
> > &HwAddressSize);
> > +  NewNetworkInterface = NULL;
> > +  *IsNewInstance = TRUE;
> > +  if (!IsListEmpty ((const
> > LIST_ENTRY*)&mEfiRedfishDiscoverNetworkInterface)) {
> > +    //
> > +    // Check if this instance already exist.
> > +    //
> > +    ThisNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetFirstNode
> > (&mEfiRedfishDiscoverNetworkInterface);
> > +    if (ThisNetworkInterface != NULL) {
> > +      while (TRUE) {
> > +        if ((CompareMem ((CONST VOID
> > *)&ThisNetworkInterface->MacAddress.Addr, (CONST VOID
> > *)&MacAddress.Addr, HwAddressSize) == 0) &&
> > +             (ThisNetworkInterface->NetworkProtocolType ==
> > NetworkProtocolType)){
> > +          NewNetworkInterface = ThisNetworkInterface;
> > +          *IsNewInstance = FALSE;
> > +          break;
> > +        }
> > +        if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface,
> > &ThisNetworkInterface->Entry)) {
> > +          NewNetworkInterface = NULL;
> > +          break;
> > +        }
> > +        ThisNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> > &ThisNetworkInterface->Entry);
> > +      };
> > +    }
> > +  }
> > +  if (NewNetworkInterface == NULL) {
> > +    //
> > +    // Create a new instance.
> > +    //
> > +    NewNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *)AllocateZeroPool (sizeof
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL));
> > +    if (NewNetworkInterface == NULL) {
> > +      return EFI_OUT_OF_RESOURCES;
> > +    }
> > +    NewNetworkInterface->HwAddressSize = HwAddressSize;
> > +    CopyMem (&NewNetworkInterface->MacAddress.Addr,
> > &MacAddress.Addr, NewNetworkInterface->HwAddressSize);
> > +    NetLibGetMacString (ControllerHandle, NULL,
> > &NewNetworkInterface->StrMacAddr);
> > +    NewNetworkInterface->VlanId = NetLibGetVlanId (ControllerHandle);
> > +  }
> > +  *NetworkInterface = NewNetworkInterface;
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  This function destory network interface
> > +
> > +
> > +  @param[in]  ThisNetworkInterface
> > EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance.
> > +
> > +  @retval EFI_STATUS
> > +**/
> > +EFI_STATUS
> > +DestroyRedfishNetwrokInterface (
> > +  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *ThisNetworkInterface
> > +  )
> > +{
> > +  EFI_STATUS Status;
> > +
> > +  Status = gBS->UninstallProtocolInterface(
> > +                  ThisNetworkInterface->OpenDriverControllerHandle,
> > +                  gRequiredProtocol
> > [ThisNetworkInterface->NetworkProtocolType].DiscoveredProtocolGuid,
> > +
> > &ThisNetworkInterface-
> >NetworkInterfaceProtocolInfo.ProtocolDiscoverId
> > +                  );
> > +  RemoveEntryList (&ThisNetworkInterface->Entry);
> > +  mNumNetworkInterface --;
> > +  FreePool (ThisNetworkInterface);
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Tests to see if the required protocols are provided on the given
> > +  controller handle.
> > +
> > +  @param[in]  This                 A pointer to the
> > EFI_DRIVER_BINDING_PROTOCOL instance.
> > +  @param[in]  ControllerHandle     The handle of the controller to test.
> > This handle
> > +                                   must support a protocol
> > interface that supplies
> > +                                   an I/O abstraction to the driver.
> > +  @retval EFI_SUCCESS              One of required protocol is found.
> > +  @retval EFI_UNSUPPORTED          None of required protocol is
> > found.
> > +**/
> > +EFI_STATUS
> > +TestForRequiredProtocols (
> > +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> > +  IN EFI_HANDLE ControllerHandle
> > +  )
> > +{
> > +  UINT32 Id;
> > +  UINTN Index;
> > +  EFI_STATUS Status;
> > +
> > +  for (Index = 0; Index < (sizeof (gRequiredProtocol) / sizeof
> > (REDFISH_DISCOVER_REQUIRED_PROTOCOL)); Index ++) {
> > +    Status = gBS->OpenProtocol (
> > +                  ControllerHandle,
> > +                  gRequiredProtocol
> > [Index].RequiredServiceBindingProtocolGuid,
> > +                  NULL,
> > +                  This->DriverBindingHandle,
> > +                  ControllerHandle,
> > +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> > +                  );
> > +    if (!EFI_ERROR (Status)) {
> > +      Status = gBS->OpenProtocol (
> > +                      ControllerHandle,
> > +                      gRequiredProtocol
> > [Index].DiscoveredProtocolGuid,
> > +                      (VOID **) &Id,
> > +                      This->DriverBindingHandle,
> > +                      ControllerHandle,
> > +                      EFI_OPEN_PROTOCOL_GET_PROTOCOL
> > +                      );
> > +      if (EFI_ERROR (Status)) {
> > +        DEBUG((DEBUG_ERROR, "%a: %s is found on this controller
> > handle.\n", __FUNCTION__, gRequiredProtocol [Index].ProtocolName));
> > +        return EFI_SUCCESS;
> > +      }
> > +    }
> > +  }
> > +  return EFI_UNSUPPORTED;
> > +}
> > +
> > +/**
> > +  Build up network interface and create corresponding service through the
> > given
> > +  controller handle.
> > +
> > +  @param[in]  This                 A pointer to the
> > EFI_DRIVER_BINDING_PROTOCOL instance.
> > +  @param[in]  ControllerHandle     The handle of the controller to test.
> > This handle
> > +                                   must support a protocol
> > interface that supplies
> > +                                   an I/O abstraction to the driver.
> > +  @retval EFI_SUCCESS              One of required protocol is found.
> > +  @retval EFI_UNSUPPORTED          None of required protocol is
> > found.
> > +  @retval EFI_UNSUPPORTED          Failed to build up network
> > interface.
> > +**/
> > +EFI_STATUS
> > +BuildupNetworkInterface (
> > +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> > +  IN EFI_HANDLE ControllerHandle
> > +  )
> > +{
> > +  UINT32 Id;
> > +  UINT32 Index;
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *NetworkInterface;
> > +  BOOLEAN IsNew;
> > +  EFI_STATUS Status;
> > +  VOID *TempInterface;
> > +  VOID **Interface;
> > +  UINT32 *ProtocolDiscoverIdPtr;
> > +  EFI_HANDLE OpenDriverAgentHandle;
> > +  EFI_HANDLE OpenDriverControllerHandle;
> > +  EFI_HANDLE *HandleOfProtocolInterfacePtr;
> > +  EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL
> > *RestExInstance;
> > +  EFI_TPL OldTpl;
> > +  BOOLEAN NewNetworkInterfaceInstalled;
> > +
> > +  NewNetworkInterfaceInstalled = FALSE;
> > +  Index = 0;
> > +  do {
> > +    Status = gBS->OpenProtocol ( // Already in list?
> > +                    ControllerHandle,
> > +                    gRequiredProtocol [Index].DiscoveredProtocolGuid,
> > +                    (VOID **) &Id,
> > +                    This->DriverBindingHandle,
> > +                    ControllerHandle,
> > +                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
> > +                    );
> > +    if (!EFI_ERROR (Status)) {
> > +      Index ++;
> > +      if (Index == (sizeof(gRequiredProtocol) /
> > sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
> > +        break;
> > +      }
> > +      continue;
> > +    }
> > +
> > +    Status = gBS->OpenProtocol (
> > +                    ControllerHandle,
> > +                    gRequiredProtocol
> > [Index].RequiredServiceBindingProtocolGuid,
> > +                    &TempInterface,
> > +                    This->DriverBindingHandle,
> > +                    ControllerHandle,
> > +                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
> > +                    );
> > +    if (EFI_ERROR (Status)) {
> > +      Index ++;
> > +      if (Index == (sizeof(gRequiredProtocol) /
> > sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
> > +        break;
> > +      }
> > +      continue;
> > +    }
> > +    if (gRequiredProtocol [Index].ProtocolType != ProtocolTypeRestEx) {
> > +      OldTpl = gBS->RaiseTPL
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
> > +      Status = CreateRedfishDiscoverNetworkInterface(ControllerHandle,
> > gRequiredProtocol [Index].ProtocolType, &IsNew, &NetworkInterface);
> > +      if (EFI_ERROR (Status)) {
> > +        gBS->RestoreTPL (OldTpl);
> > +        return Status;
> > +      }
> > +      NetworkInterface->NetworkProtocolType = gRequiredProtocol
> > [Index].ProtocolType;
> > +      NetworkInterface->OpenDriverAgentHandle =
> > This->DriverBindingHandle;
> > +      NetworkInterface->OpenDriverControllerHandle = ControllerHandle;
> > +      NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolGuid = \
> > +        *gRequiredProtocol [Index].RequiredProtocolGuid;
> > +
> > NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolServiceGuid = \
> > +        *gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid;
> > +      ProtocolDiscoverIdPtr =
> > &NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolDiscoverId;
> > +      OpenDriverAgentHandle =
> > NetworkInterface->OpenDriverAgentHandle;
> > +      OpenDriverControllerHandle =
> > NetworkInterface->OpenDriverControllerHandle;
> > +      HandleOfProtocolInterfacePtr =
> > &NetworkInterface-
> >NetworkInterfaceProtocolInfo.ProtocolControllerHandle
> > ;
> > +      Interface =
> > &NetworkInterface-
> >NetworkInterfaceProtocolInfo.NetworkProtocolInterfac
> > e;
> > +      NewNetworkInterfaceInstalled = TRUE;
> > +      if (IsNew) {
> > +        InsertTailList (&mEfiRedfishDiscoverNetworkInterface,
> > &NetworkInterface->Entry);
> > +        mNumNetworkInterface ++;
> > +      }
> > +      gBS->RestoreTPL (OldTpl);
> > +    } else {
> > +      // Record REST_EX instance. REST_EX is created when clinet asks for
> > Redfish service discovery.
> > +      // Redfish Service Discover protocol will match REST EX to the
> > corresponding EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > +      // when discovery.
> > +
> > +      RestExInstance =
> > (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL
> *)AllocateZeroPool
> > (sizeof (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL));
> > +      if (RestExInstance == NULL) {
> > +        return EFI_OUT_OF_RESOURCES;
> > +      }
> > +      RestExInstance->OpenDriverAgentHandle =
> > This->DriverBindingHandle;
> > +      RestExInstance->OpenDriverControllerHandle = ControllerHandle;
> > +      RestExInstance->RestExControllerHandle = ControllerHandle;
> > +      InitializeListHead (&RestExInstance->Entry);
> > +      InsertTailList (&mEfiRedfishDiscoverRestExInstance,
> > &RestExInstance->Entry);
> > +      mNumRestExInstance ++;
> > +      ProtocolDiscoverIdPtr = &RestExInstance->RestExId;
> > +      OpenDriverAgentHandle =
> > RestExInstance->OpenDriverAgentHandle;
> > +      OpenDriverControllerHandle =
> > RestExInstance->OpenDriverControllerHandle;
> > +      HandleOfProtocolInterfacePtr =
> > &RestExInstance->RestExChildHandle;
> > +      Interface = (VOID **)&RestExInstance->RestExProtocolInterface;
> > +    }
> > +    Status = gBS->InstallProtocolInterface (
> > +                    &ControllerHandle,
> > +                    gRequiredProtocol [Index].DiscoveredProtocolGuid,
> > +                    EFI_NATIVE_INTERFACE,
> > +                    ProtocolDiscoverIdPtr
> > +                    );
> > +    if (EFI_ERROR (Status)) {
> > +      Index ++;
> > +      if (Index == (sizeof(gRequiredProtocol) /
> > sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
> > +        break;
> > +      }
> > +      continue;
> > +    }
> > +    //
> > +    // Create service binding child and open it BY_DRIVER.
> > +    //
> > +    Status = NetLibCreateServiceChild (
> > +              ControllerHandle,
> > +              This->ImageHandle,
> > +              gRequiredProtocol
> > [Index].RequiredServiceBindingProtocolGuid,
> > +              HandleOfProtocolInterfacePtr
> > +              );
> > +    if (!EFI_ERROR (Status)) {
> > +      Status = gBS->OpenProtocol (
> > +                    *HandleOfProtocolInterfacePtr,
> > +                    gRequiredProtocol [Index].RequiredProtocolGuid,
> > +                    Interface,
> > +                    OpenDriverAgentHandle,
> > +                    OpenDriverControllerHandle,
> > +                    EFI_OPEN_PROTOCOL_BY_DRIVER
> > +                    );
> > +      if (!EFI_ERROR (Status)) {
> > +        if (EfiRedfishDiscoverProtocolHandle == NULL &&
> > +            (gRequiredProtocol [Index].ProtocolType ==
> > ProtocolTypeRestEx) &&
> > +            !IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)
> > +            ) {
> > +          // Install the fisrt Redfish Discover Protocol when EFI REST EX
> > protcol is discovered.
> > +          // This ensures EFI REST EX is ready while
> > EFI_REDFISH_DISCOVER_PROTOCOL consumer acquires
> > +          // Redfish serivce over network interface.
> > +
> > +          Status = gBS->InstallProtocolInterface (
> > +                          &EfiRedfishDiscoverProtocolHandle,
> > +                          &gEfiRedfishDiscoverProtocolGuid,
> > +                          EFI_NATIVE_INTERFACE,
> > +                          (VOID *)&mRedfishDiscover
> > +                          );
> > +        } else if (EfiRedfishDiscoverProtocolHandle != NULL &&
> > NewNetworkInterfaceInstalled) {
> > +           Status = gBS->ReinstallProtocolInterface (
> > +                            EfiRedfishDiscoverProtocolHandle,
> > +                            &gEfiRedfishDiscoverProtocolGuid,
> > +                            (VOID *)&mRedfishDiscover,
> > +                            (VOID *)&mRedfishDiscover
> > +                            );
> > +           NewNetworkInterfaceInstalled = FALSE;
> > +        }
> > +      }
> > +      return Status;
> > +    } else {
> > +      Index ++;
> > +      if (Index == (sizeof(gRequiredProtocol) /
> > sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
> > +        break;
> > +      }
> > +      continue;
> > +    }
> > +  } while (Index < (sizeof(gRequiredProtocol) /
> > sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL)));
> > +  return EFI_UNSUPPORTED;
> > +}
> > +/**
> > +  Close the protocol opened for Redfish discovery. This function also
> > destories
> > +  the network services.
> > +
> > +  @param[in]  ThisBindingProtocol     A pointer to the
> > EFI_DRIVER_BINDING_PROTOCOL instance.
> > +  @param[in]  ControllerHandle        The handle of the controller to
> > test. This handle
> > +                                      must support a protocol
> > interface that supplies
> > +                                      an I/O abstraction to the
> > driver.
> > +  @param[in]  ThisRequiredProtocol    Pointer to the instance of
> > REDFISH_DISCOVER_REQUIRED_PROTOCOL.
> > +  @param[in]  DriverAgentHandle      Driver agent handle which used
> > to open protocol earlier.
> > +  @param[in]  DriverControllerHandle Driver controller handle which used
> > to open protocol earlier.
> > +
> > +  @retval EFI_SUCCESS                Prorocol is closed successfully.
> > +  @retval Others                     Prorocol is closed
> > unsuccessfully.
> > +
> > +**/
> > +EFI_STATUS
> > +CloseProtocolService (
> > +  IN EFI_DRIVER_BINDING_PROTOCOL  *ThisBindingProtocol,
> > +  IN EFI_HANDLE  ControllerHandle,
> > +  IN REDFISH_DISCOVER_REQUIRED_PROTOCOL *ThisRequiredProtocol,
> > +  IN EFI_HANDLE DriverAgentHandle,
> > +  IN EFI_HANDLE DriverControllerHandle
> > +)
> > +{
> > +  EFI_STATUS Status;
> > +
> > +  Status = gBS->CloseProtocol (
> > +                   ControllerHandle,
> > +                   ThisRequiredProtocol->RequiredProtocolGuid,
> > +                   DriverAgentHandle,
> > +                   DriverControllerHandle
> > +                   );
> > +  if (!EFI_ERROR (Status)) {
> > +    NetLibDestroyServiceChild(
> > +      ControllerHandle,
> > +      ThisBindingProtocol->ImageHandle,
> > +      ThisRequiredProtocol->RequiredServiceBindingProtocolGuid,
> > +      ControllerHandle
> > +      );
> > +  }
> > +  return Status;
> > +}
> > +/**
> > +  Stop the services on network interface.
> > +
> > +  @param[in]  ThisBindingProtocol  A pointer to the
> > EFI_DRIVER_BINDING_PROTOCOL instance.
> > +  @param[in]  ControllerHandle     The handle of the controller to test.
> > This handle
> > +                                   must support a protocol
> > interface that supplies
> > +                                   an I/O abstraction to the driver.
> > +  @retval EFI_SUCCESS              One of required protocol is found.
> > +  @retval Others                   Faile to stop the services on
> > network interface.
> > +**/
> > +EFI_STATUS
> > +StopServiceOnNetworkInterface (
> > +  IN EFI_DRIVER_BINDING_PROTOCOL  *ThisBindingProtocol,
> > +  IN EFI_HANDLE ControllerHandle
> > +  )
> > +{
> > +  UINT32 Index;
> > +  EFI_STATUS Status;
> > +  VOID *Interface;
> > +  EFI_TPL OldTpl;
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *ThisNetworkInterface;
> > +  EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL
> > *RestExInstance;
> > +
> > +  for (Index = 0; Index < (sizeof (gRequiredProtocol) / sizeof
> > (REDFISH_DISCOVER_REQUIRED_PROTOCOL)); Index ++) {
> > +    Status = gBS->HandleProtocol (
> > +                  ControllerHandle,
> > +                  gRequiredProtocol [Index].RequiredProtocolGuid,
> > +                  (VOID **)&Interface
> > +                  );
> > +    if (!EFI_ERROR (Status)) {
> > +      if (gRequiredProtocol [Index].ProtocolType != ProtocolTypeRestEx) {
> > +        if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
> > +          return EFI_NOT_FOUND;
> > +        }
> > +        OldTpl = gBS->RaiseTPL
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
> > +        ThisNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetFirstNode
> > (&mEfiRedfishDiscoverNetworkInterface);
> > +        while (TRUE) {
> > +          if
> > (ThisNetworkInterface-
> >NetworkInterfaceProtocolInfo.ProtocolControllerHan
> > dle == ControllerHandle) {
> > +
> > +            Status = CloseProtocolService ( // Close protocol and destroy
> > service.
> > +                       ThisBindingProtocol,
> > +                       ControllerHandle,
> > +                       &gRequiredProtocol [Index],
> > +
> > ThisNetworkInterface->OpenDriverAgentHandle,
> > +
> > ThisNetworkInterface->OpenDriverControllerHandle
> > +                       );
> > +            if (!EFI_ERROR (Status)) {
> > +              Status = DestroyRedfishNetwrokInterface
> > (ThisNetworkInterface);
> > +            }
> > +            gBS->RestoreTPL (OldTpl);
> > +            // Reinstall Redfish Discover protocol to notify network
> > +            // interface change.
> > +
> > +            Status = gBS->ReinstallProtocolInterface (
> > +                            EfiRedfishDiscoverProtocolHandle,
> > +                            &gEfiRedfishDiscoverProtocolGuid,
> > +                            (VOID *)&mRedfishDiscover,
> > +                            (VOID *)&mRedfishDiscover
> > +                            );
> > +            if (EFI_ERROR (Status)) {
> > +              DEBUG((DEBUG_ERROR, "%a: Reinstall
> > gEfiRedfishDiscoverProtocolGuid fail.", __FUNCTION__));
> > +            }
> > +            return Status;
> > +          }
> > +          if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface,
> > &ThisNetworkInterface->Entry)) {
> > +            break;
> > +          }
> > +          ThisNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface,
> > &ThisNetworkInterface->Entry);
> > +        };
> > +        gBS->RestoreTPL (OldTpl);
> > +      } else {
> > +        if (IsListEmpty (&mEfiRedfishDiscoverRestExInstance)) {
> > +          return EFI_NOT_FOUND;
> > +        }
> > +        OldTpl = gBS->RaiseTPL
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
> > +        RestExInstance =
> > (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)GetFirstNode
> > (&mEfiRedfishDiscoverRestExInstance);
> > +        while (TRUE) {
> > +          if (RestExInstance->RestExChildHandle == ControllerHandle) {
> > +            Status = CloseProtocolService ( // Close REST_EX protocol.
> > +                       ThisBindingProtocol,
> > +                       ControllerHandle,
> > +                       &gRequiredProtocol [Index],
> > +                       RestExInstance->OpenDriverAgentHandle,
> > +                       RestExInstance->OpenDriverControllerHandle
> > +                       );
> > +            RemoveEntryList (&RestExInstance->Entry);
> > +            FreePool ((VOID *)RestExInstance);
> > +            mNumRestExInstance --;
> > +            gBS->RestoreTPL (OldTpl);
> > +            return Status;
> > +          }
> > +          if (IsNodeAtEnd (&mEfiRedfishDiscoverRestExInstance,
> > &RestExInstance->Entry)) {
> > +            break;
> > +          }
> > +          RestExInstance =
> > (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL
> > *)GetNextNode(&mEfiRedfishDiscoverRestExInstance,
> > &RestExInstance->Entry);
> > +        };
> > +        gBS->RestoreTPL (OldTpl);
> > +      }
> > +    }
> > +  }
> > +  return EFI_NOT_FOUND;
> > +}
> > +/**
> > +  Tests to see if this driver supports a given controller. If a child
> device is
> > provided,
> > +  it further tests to see if this driver supports creating a handle for
> the
> > specified child device.
> > +
> > +  This function checks to see if the driver specified by This supports
> the
> > device specified by
> > +  ControllerHandle. Drivers will typically use the device path attached
> to
> > +  ControllerHandle and/or the services from the bus I/O abstraction
> > attached to
> > +  ControllerHandle to determine if the driver supports ControllerHandle.
> > This function
> > +  may be called many times during platform initialization. In order to
> reduce
> > boot times, the tests
> > +  performed by this function must be very small, and take as little time
> as
> > possible to execute. This
> > +  function must not change the state of any hardware devices, and this
> > function must be aware that the
> > +  device specified by ControllerHandle may already be managed by the
> > same driver or a
> > +  different driver. This function must match its calls to AllocatePages()
> with
> > FreePages(),
> > +  AllocatePool() with FreePool(), and OpenProtocol() with
> CloseProtocol().
> > +  Because ControllerHandle may have been previously started by the
> same
> > driver, if a protocol is
> > +  already in the opened state, then it must not be closed with
> > CloseProtocol(). This is required
> > +  to guarantee the state of ControllerHandle is not modified by this
> > function.
> > +
> > +  @param[in]  This                 A pointer to the
> > EFI_DRIVER_BINDING_PROTOCOL instance.
> > +  @param[in]  ControllerHandle     The handle of the controller to test.
> > This handle
> > +                                   must support a protocol
> > interface that supplies
> > +                                   an I/O abstraction to the driver.
> > +  @param[in]  RemainingDevicePath  A pointer to the remaining portion
> > of a device path.  This
> > +                                   parameter is ignored by device
> > drivers, and is optional for bus
> > +                                   drivers. For bus drivers, if this
> > parameter is not NULL, then
> > +                                   the bus driver must determine if
> > the bus controller specified
> > +                                   by ControllerHandle and the
> > child controller specified
> > +                                   by RemainingDevicePath are
> > both supported by this
> > +                                   bus driver.
> > +
> > +  @retval EFI_SUCCESS              The device specified by
> > ControllerHandle and
> > +                                   RemainingDevicePath is
> > supported by the driver specified by This.
> > +  @retval EFI_ALREADY_STARTED      The device specified by
> > ControllerHandle and
> > +                                   RemainingDevicePath is already
> > being managed by the driver
> > +                                   specified by This.
> > +  @retval EFI_ACCESS_DENIED        The device specified by
> > ControllerHandle and
> > +                                   RemainingDevicePath is already
> > being managed by a different
> > +                                   driver or an application that
> > requires exclusive access.
> > +                                   Currently not implemented.
> > +  @retval EFI_UNSUPPORTED          The device specified by
> > ControllerHandle and
> > +                                   RemainingDevicePath is not
> > supported by the driver specified by This.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishDiscoverDriverBindingSupported (
> > +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> > +  IN EFI_HANDLE                   ControllerHandle,
> > +  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
> > +  )
> > +{
> > +  return TestForRequiredProtocols (This, ControllerHandle);
> > +}
> > +
> > +/**
> > +  Starts a device controller or a bus controller.
> > +
> > +  The Start() function is designed to be invoked from the EFI boot
> service
> > ConnectController().
> > +  As a result, much of the error checking on the parameters to Start()
> has
> > been moved into this
> > +  common boot service. It is legal to call Start() from other locations,
> > +  but the following calling restrictions must be followed, or the system
> > behavior will not be deterministic.
> > +  1. ControllerHandle must be a valid EFI_HANDLE.
> > +  2. If RemainingDevicePath is not NULL, then it must be a pointer to a
> > naturally aligned
> > +     EFI_DEVICE_PATH_PROTOCOL.
> > +  3. Prior to calling Start(), the Supported() function for the driver
> specified
> > by This must
> > +     have been called with the same calling parameters, and Supported()
> > must have returned EFI_SUCCESS.
> > +
> > +  @param[in]  This                 A pointer to the
> > EFI_DRIVER_BINDING_PROTOCOL instance.
> > +  @param[in]  ControllerHandle     The handle of the controller to start.
> > This handle
> > +                                   must support a protocol
> > interface that supplies
> > +                                   an I/O abstraction to the driver.
> > +  @param[in]  RemainingDevicePath  A pointer to the remaining portion
> > of a device path.  This
> > +                                   parameter is ignored by device
> > drivers, and is optional for bus
> > +                                   drivers. For a bus driver, if this
> > parameter is NULL, then handles
> > +                                   for all the children of Controller
> > are created by this driver.
> > +                                   If this parameter is not NULL
> > and the first Device Path Node is
> > +                                   not the End of Device Path Node,
> > then only the handle for the
> > +                                   child device specified by the first
> > Device Path Node of
> > +                                   RemainingDevicePath is created
> > by this driver.
> > +                                   If the first Device Path Node of
> > RemainingDevicePath is
> > +                                   the End of Device Path Node, no
> > child handle is created by this
> > +                                   driver.
> > +
> > +  @retval EFI_SUCCESS              The device was started.
> > +  @retval EFI_DEVICE_ERROR         The device could not be started
> > due to a device error.Currently not implemented.
> > +  @retval EFI_OUT_OF_RESOURCES     The request could not be
> > completed due to a lack of resources.
> > +  @retval Others                   The driver failded to start the
> > device.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishDiscoverDriverBindingStart (
> > +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> > +  IN EFI_HANDLE                   ControllerHandle,
> > +  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
> > +  )
> > +{
> > +  return BuildupNetworkInterface (This, ControllerHandle);
> > +}
> > +
> > +/**
> > +  Stops a device controller or a bus controller.
> > +
> > +  The Stop() function is designed to be invoked from the EFI boot service
> > DisconnectController().
> > +  As a result, much of the error checking on the parameters to Stop() has
> > been moved
> > +  into this common boot service. It is legal to call Stop() from other
> locations,
> > +  but the following calling restrictions must be followed, or the system
> > behavior will not be deterministic.
> > +  1. ControllerHandle must be a valid EFI_HANDLE that was used on a
> > previous call to this
> > +     same driver's Start() function.
> > +  2. The first NumberOfChildren handles of ChildHandleBuffer must all be
> a
> > valid
> > +     EFI_HANDLE. In addition, all of these handles must have been created
> > in this driver's
> > +     Start() function, and the Start() function must have called
> > OpenProtocol() on
> > +     ControllerHandle with an Attribute of
> > EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
> > +
> > +  @param[in]  This              A pointer to the
> > EFI_DRIVER_BINDING_PROTOCOL instance.
> > +  @param[in]  ControllerHandle  A handle to the device being stopped.
> > The handle must
> > +                                support a bus specific I/O protocol
> > for the driver
> > +                                to use to stop the device.
> > +  @param[in]  NumberOfChildren  The number of child device handles in
> > ChildHandleBuffer.
> > +  @param[in]  ChildHandleBuffer An array of child handles to be freed.
> > May be NULL
> > +                                if NumberOfChildren is 0.
> > +
> > +  @retval EFI_SUCCESS           The device was stopped.
> > +  @retval EFI_DEVICE_ERROR      The device could not be stopped due
> > to a device error.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishDiscoverDriverBindingStop (
> > +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> > +  IN EFI_HANDLE                   ControllerHandle,
> > +  IN UINTN                        NumberOfChildren,
> > +  IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
> > +  )
> > +{
> > +  return StopServiceOnNetworkInterface (This, ControllerHandle);
> > +}
> > +
> > +EFI_DRIVER_BINDING_PROTOCOL gRedfishDiscoverDriverBinding = {
> > +  RedfishDiscoverDriverBindingSupported,
> > +  RedfishDiscoverDriverBindingStart,
> > +  RedfishDiscoverDriverBindingStop,
> > +  REDFISH_DISCOVER_VERSION,
> > +  NULL,
> > +  NULL
> > +};
> > +
> > +/**
> > +  This is the declaration of an EFI image entry point.
> > +
> > +  @param  ImageHandle           The firmware allocated handle for
> > the UEFI image.
> > +  @param  SystemTable           A pointer to the EFI System Table.
> > +
> > +  @retval EFI_SUCCESS           The operation completed successfully.
> > +  @retval Others                An unexpected error occurred.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishDiscoverEntryPoint (
> > +  IN EFI_HANDLE        ImageHandle,
> > +  IN EFI_SYSTEM_TABLE  *SystemTable
> > +  )
> > +{
> > +  EFI_STATUS Status;
> > +
> > +  Status = EFI_SUCCESS;
> > +  InitializeListHead (&mRedfishDiscoverList);
> > +  InitializeListHead (&mRedfishInstanceList);
> > +  InitializeListHead (&mEfiRedfishDiscoverNetworkInterface);
> > +  InitializeListHead (&mEfiRedfishDiscoverRestExInstance);
> > +  //
> > +  // Install binding protoocl to obtain UDP and REST EX protocol.
> > +  //
> > +  Status = EfiLibInstallDriverBindingComponentName2 (
> > +             ImageHandle,
> > +             SystemTable,
> > +             &gRedfishDiscoverDriverBinding,
> > +             ImageHandle,
> > +             &gRedfishDiscoverComponentName,
> > +             &gRedfishDiscoverComponentName2
> > +             );
> > +  return Status;
> > +}
> > +
> > +/**
> > +  This is the unload handle for Redfish discover module.
> > +
> > +  Disconnect the driver specified by ImageHandle from all the devices in
> the
> > handle database.
> > +  Uninstall all the protocols installed in the driver entry point.
> > +
> > +  @param[in] ImageHandle           The drivers' driver image.
> > +
> > +  @retval    EFI_SUCCESS           The image is unloaded.
> > +  @retval    Others                Failed to unload the image.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishDiscoverUnload (
> > +  IN EFI_HANDLE ImageHandle
> > +  )
> > +{
> > +  EFI_STATUS Status;
> > +  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> > *ThisNetworkInterface;
> > +
> > +  Status = EFI_SUCCESS;
> > +  // Destroy all network interfaces found by EFI Redfish Discover driver
> and
> > +  // stop services created for Redfish Discover.
> > +
> > +  while (!IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
> > +    ThisNetworkInterface =
> > (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
> *)GetFirstNode
> > (&mEfiRedfishDiscoverNetworkInterface);
> > +    StopServiceOnNetworkInterface (&gRedfishDiscoverDriverBinding,
> > ThisNetworkInterface-
> >NetworkInterfaceProtocolInfo.ProtocolControllerHan
> > dle);
> > +  };
> > +  // Disconnect EFI Redfish discover driver controller to notify the
> > +  // clinet which uses .EFI Redfish discover protocol.
> > +
> > +  if (EfiRedfishDiscoverProtocolHandle != NULL) {
> > +    //
> > +    // Notify user EFI_REDFISH_DISCOVER_PROTOCOL is unloaded.
> > +    //
> > +    gBS->DisconnectController (EfiRedfishDiscoverProtocolHandle, NULL,
> > NULL);
> > +    Status = gBS->UninstallProtocolInterface(
> > +                    EfiRedfishDiscoverProtocolHandle,
> > +                    &gEfiRedfishDiscoverProtocolGuid,
> > +                    (VOID *)&mRedfishDiscover
> > +                    );
> > +  }
> > +  return Status;
> > +}
> > diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
> > b/RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
> > new file mode 100644
> > index 0000000000..f3ad36ec3a
> > --- /dev/null
> > +++ b/RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
> > @@ -0,0 +1,118 @@
> > +/** @file
> > +  RedfishSmbiosHostInterface.c
> > +
> > +  Discover Redfish SMBIOS Host Interface.
> > +
> > +  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> > +
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include "RedfishDiscoverInternal.h"
> > +
> > +SMBIOS_TABLE_TYPE42  *mType42Record;
> > +
> > +/**
> > +  The function gets information reported in Redfish Host Interface.
> > +
> > +  It simply frees the packet.
> > +
> > +  @param[in]  Smbios           SMBIOS protocol.
> > +  @param[out] DeviceDescriptor Pointer to REDFISH_INTERFACE_DATA.
> > +  @param[out] ProtocolData     Pointer to
> > REDFISH_OVER_IP_PROTOCOL_DATA.
> > +
> > +  @retval EFI_SUCCESS    Get host interface succesfully.
> > +  @retval Otherwise      Fail to tet host interface.
> > +
> > +**/
> > +EFI_STATUS
> > +RedfishGetHostInterfaceProtocolData (
> > +  IN EFI_SMBIOS_PROTOCOL              *Smbios,
> > +  OUT REDFISH_INTERFACE_DATA          **DeviceDescriptor,
> > +  OUT REDFISH_OVER_IP_PROTOCOL_DATA   **ProtocolData
> > +  )
> > +{
> > +  EFI_STATUS                        Status;
> > +  EFI_SMBIOS_HANDLE                 SmbiosHandle;
> > +  EFI_SMBIOS_TABLE_HEADER           *Record;
> > +  UINT16                            Offset;
> > +  UINT8                             *RecordTmp;
> > +  UINT8                             ProtocolLength;
> > +  UINT8                             SpecificDataLen;
> > +
> > +  if ((Smbios == NULL) || (ProtocolData == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
> > +  Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record,
> > NULL);
> > +  while (!EFI_ERROR (Status) && SmbiosHandle !=
> > SMBIOS_HANDLE_PI_RESERVED) {
> > +    if (Record->Type ==
> > SMBIOS_TYPE_MANAGEMENT_CONTROLLER_HOST_INTERFACE) {
> > +      //
> > +      // Check Interface Type, should be Network Host Interface = 40h
> > +      //
> > +      mType42Record = (SMBIOS_TABLE_TYPE42 *) Record;
> > +      if (mType42Record->InterfaceType ==
> > MCHostInterfaceTypeNetworkHostInterface) {
> > +        ASSERT (Record->Length >= 9);
> > +        Offset = 5;
> > +        RecordTmp = (UINT8 *) Record + Offset;
> > +        //
> > +        // Get interface specific data length.
> > +        //
> > +        SpecificDataLen = *RecordTmp;
> > +        Offset += 1;
> > +        RecordTmp = (UINT8 *) Record + Offset;
> > +
> > +        //
> > +        // Check Device Type, only PCI/PCIe Network Interface v2 is
> > supported now.
> > +        //
> > +        if (*RecordTmp ==
> > REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2) {
> > +          ASSERT (SpecificDataLen == sizeof
> > (PCI_OR_PCIE_INTERFACE_DEVICE_DESCRIPTOR_V2) + 1);
> > +          *DeviceDescriptor = (REDFISH_INTERFACE_DATA *)RecordTmp;
> > +          Offset = Offset + SpecificDataLen;
> > +          RecordTmp = (UINT8 *) Record + Offset;
> > +          //
> > +          // Check Protocol count. if > 1, only use the first protocol.
> > +          //
> > +          ASSERT (*RecordTmp == 1);
> > +          Offset += 1;
> > +          RecordTmp = (UINT8 *) Record + Offset;
> > +          //
> > +          // Check protocol identifier.
> > +          //
> > +          if (*RecordTmp == MCHostInterfaceProtocolTypeRedfishOverIP)
> > {
> > +            Offset += 1;
> > +            RecordTmp = (UINT8 *) Record + Offset;
> > +            ProtocolLength = *RecordTmp;
> > +
> > +            Offset += 1;
> > +            RecordTmp = (UINT8 *) Record + Offset;
> > +
> > +            //
> > +            // This SMBIOS record is invalid, if the length of protocol
> > specific data for
> > +            // Redfish Over IP protocol is wrong.
> > +            //
> > +            if ((*(RecordTmp + 90) + sizeof
> > (REDFISH_OVER_IP_PROTOCOL_DATA) - 1) != ProtocolLength) {
> > +              return EFI_SECURITY_VIOLATION;
> > +            }
> > +
> > +            Offset += ProtocolLength;
> > +            //
> > +            // This SMBIOS record is invalid, if the length is smaller
> than
> > the offset.
> > +            //
> > +            if (Offset > mType42Record->Hdr.Length) {
> > +              return EFI_SECURITY_VIOLATION;
> > +            }
> > +            *ProtocolData = (REDFISH_OVER_IP_PROTOCOL_DATA
> > *)RecordTmp;
> > +            return EFI_SUCCESS;
> > +          }
> > +        }
> > +      }
> > +    }
> > +    Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record,
> > NULL);
> > +  }
> > +
> > +  *ProtocolData = NULL;
> > +  return EFI_NOT_FOUND;
> > +}
> > --
> > 2.17.1
> >
> >
> >
> >
> >
> 
> 
> 
> 
> 
> 
> 



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#73764): https://edk2.groups.io/g/devel/message/73764
Mute This Topic: https://groups.io/mt/81909823/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-


Re: [edk2-devel] [PATCH] RedfishPkg/RedfishDiscoverDxe: EFI Redfish Discover Protocol
Posted by Nickle Wang 3 years ago
Reviewed-by: Nickle Wang <nickle.wang@hpe.com>

Thanks,
Nickle

-----Original Message-----
From: Chang, Abner (HPS SW/FW Technologist) <abner.chang@hpe.com> 
Sent: Friday, March 26, 2021 12:54 PM
To: devel@edk2.groups.io
Cc: Wang, Nickle (HPS SW) <nickle.wang@hpe.com>; Jiaxin Wu <jiaxin.wu@intel.com>; Siyuan Fu <siyuan.fu@intel.com>; Fan Wang <fan.wang@intel.com>; Jiewen Yao <jiewen.yao@intel.com>
Subject: [PATCH] RedfishPkg/RedfishDiscoverDxe: EFI Redfish Discover Protocol

EDK2 EFI Redfish Discover Protocol implementation. Refer to UEFI spec 2.9
section 31.1.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Cc: Nickle Wang <nickle.wang@hpe.com>
Cc: Jiaxin Wu <jiaxin.wu@intel.com>
Cc: Siyuan Fu <siyuan.fu@intel.com>
Cc: Fan Wang <fan.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
---
 RedfishPkg/RedfishComponents.dsc.inc          |    3 +-
 RedfishPkg/Redfish.fdf.inc                    |    3 +-
 .../RedfishDiscoverDxe/RedfishDiscoverDxe.inf |   55 +
 .../RedfishDiscoverInternal.h                 |  234 ++
 RedfishPkg/RedfishDiscoverDxe/ComponentName.c |  218 ++
 .../RedfishDiscoverDxe/RedfishDiscoverDxe.c   | 1910 +++++++++++++++++
 .../RedfishSmbiosHostInterface.c              |  118 +
 7 files changed, 2539 insertions(+), 2 deletions(-)
 create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
 create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
 create mode 100644 RedfishPkg/RedfishDiscoverDxe/ComponentName.c
 create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
 create mode 100644 RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c

diff --git a/RedfishPkg/RedfishComponents.dsc.inc b/RedfishPkg/RedfishComponents.dsc.inc
index 08f1d3bc32..6f3b055aba 100644
--- a/RedfishPkg/RedfishComponents.dsc.inc
+++ b/RedfishPkg/RedfishComponents.dsc.inc
@@ -6,7 +6,7 @@
 # of EDKII Redfish drivers according to the value of flags described in
 # "RedfishDefines.dsc.inc".
 #
-# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
+# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
 #
 #    SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -17,4 +17,5 @@
   RedfishPkg/RedfishHostInterfaceDxe/RedfishHostInterfaceDxe.inf
   RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf
   RedfishPkg/RedfishCredentialDxe/RedfishCredentialDxe.inf
+  RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
 !endif
diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc
index a64fd119a9..205c3101c0 100644
--- a/RedfishPkg/Redfish.fdf.inc
+++ b/RedfishPkg/Redfish.fdf.inc
@@ -5,7 +5,7 @@
 # by using "!include RedfishPkg/RedfisLibs.fdf.inc" to specify the module instances
 # to be built in the firmware volume.
 #
-# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
+# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
 #
 #    SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -15,4 +15,5 @@
   INF RedfishPkg/RedfishHostInterfaceDxe/RedfishHostInterfaceDxe.inf
   INF RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf
   INF RedfishPkg/RedfishCredentialDxe/RedfishCredentialDxe.inf
+  INF RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
 !endif
diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
new file mode 100644
index 0000000000..345bacf44d
--- /dev/null
+++ b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf
@@ -0,0 +1,55 @@
+## @file
+#  Implementation of EFI_REDFISH_DISCOVER_PROTOCOL interfaces.
+#
+#  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION               = 0x0001001b
+  BASE_NAME                 = RedfishDiscoverDxe
+  FILE_GUID                 = 28A76FE5-43D7-48A3-9714-C1B7BDD6DFB6
+  MODULE_TYPE               = UEFI_DRIVER
+  VERSION_STRING            = 1.0
+  ENTRY_POINT               = RedfishDiscoverEntryPoint
+  UNLOAD_IMAGE              = RedfishDiscoverUnload
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  NetworkPkg/NetworkPkg.dec
+  RedfishPkg/RedfishPkg.dec
+
+[Sources]
+  ComponentName.c
+  RedfishDiscoverDxe.c
+  RedfishSmbiosHostInterface.c
+  RedfishDiscoverInternal.h
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  PrintLib
+  RestExLib
+  UefiLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+
+[Protocols]
+  gEfiRestExServiceBindingProtocolGuid            ## Consuming
+  gEfiRestExProtocolGuid                          ## Consuming
+  gEfiTcp4ServiceBindingProtocolGuid              ## Consuming
+  gEfiTcp4ProtocolGuid                            ## Consuming
+  gEfiTcp6ServiceBindingProtocolGuid              ## Consuming
+  gEfiTcp6ProtocolGuid                            ## Consuming
+  gEfiRedfishDiscoverProtocolGuid                 ## Prodcuing
+  gEfiSmbiosProtocolGuid                          ## Consuming
+  gEfiDriverBindingProtocolGuid                   ## Consuming
+
+[Pcd]
+  gEfiRedfishPkgTokenSpaceGuid.PcdRedfishDiscoverAccessModeInBand ## CONSUMES
+
diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
new file mode 100644
index 0000000000..cf69d9231a
--- /dev/null
+++ b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h
@@ -0,0 +1,234 @@
+/** @file
+  This file defines the EFI Redfish Discover Protocol interface.
+
+  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EFI_REDFISH_DISCOVER_INTERNAL_H_
+#define EFI_REDFISH_DISCOVER_INTERNAL_H_
+
+#include <Uefi.h>
+
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/RedfishDiscover.h>
+#include <Protocol/Smbios.h>
+#include <Protocol/Tcp4.h>
+#include <Protocol/Tcp6.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NetLib.h>
+#include <Library/PrintLib.h>
+#include <Library/RestExLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+#include <IndustryStandard/RedfishHostInterface.h>
+
+#define REDFISH_DISCOVER_VERSION  0x00010000
+#define EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL TPL_NOTIFY
+
+//
+//GUID definitions
+//
+
+#define EFI_REDFISH_DISCOVER_TCP4_INSTANCE_GUID \
+  { \
+    0xfbab97a4, 0x4c6a, 0xf8e8, { 0xf2, 0x25, 0x42, 0x8a, 0x80, 0x3f, 0xb6, 0xaa } \
+  }
+
+#define EFI_REDFISH_DISCOVER_TCP6_INSTANCE_GUID \
+  { \
+    0xbe513b6d, 0x41c1, 0x96Ed, { 0x8d, 0xaf, 0x3e, 0x89, 0xc5, 0xf5, 0x02, 0x25 } \
+  }
+
+#define EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_GUID \
+  { \
+    0xc44a6076, 0xd42a, 0x4d54, { 0x85, 0x6d, 0x98, 0x8a, 0x85, 0x8f, 0xa1, 0x11 } \
+  }
+
+extern EFI_COMPONENT_NAME_PROTOCOL   gRedfishDiscoverComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gRedfishDiscoverComponentName2;
+extern EFI_UNICODE_STRING_TABLE      *gRedfishDiscoverControllerNameTable;
+
+//
+// Enumeration of network protocols
+// required for the Redfish service discovery.
+//
+typedef enum {
+  ProtocolTypeTcp4 = 0, ///< Network protocol TCPv4.
+  ProtocolTypeTcp6,     ///< Network protocol TCCv6.
+  ProtocolTypeRestEx,   ///< REST EX over network protocol.
+  MaxProtocolType
+} NETWORK_INTERFACE_PROTOCOL_TYPE;
+
+//
+// Network protocol information installed on
+// the network interface.
+//
+typedef struct {
+  EFI_GUID ProtocolGuid;                ///< Network protocol GUID.
+  EFI_GUID ProtocolServiceGuid;         ///< Network protocol service GUID.
+  UINT32   ProtocolDiscoverId;          ///< The identifier installed on network protocol handle.
+  EFI_HANDLE ProtocolControllerHandle;  ///< The controller handle on network protocol.
+  VOID *NetworkProtocolInterface;       ///< The protocol interface of network protocol.
+} REDFISH_DISCOVER_NETWORK_INTERFACE_PROTOCOL;
+
+//
+// Internal structure used to maintain network
+// interface properties.
+//
+typedef struct {
+  LIST_ENTRY      Entry;                        ///< Link list entry.
+  EFI_HANDLE      OpenDriverAgentHandle;        ///< The agent to open network protocol.
+  EFI_HANDLE      OpenDriverControllerHandle;   ///< The controller handle to open network protocol.
+  UINTN           HwAddressSize;                ///< The size of network interface hardware address.
+  EFI_MAC_ADDRESS MacAddress;                   ///< MAC address of network interface.
+  CHAR16          *StrMacAddr;                  ///< String to MAC address of network interface.
+  BOOLEAN         GotSubnetInfo;                ///< Indicates sub net information is retrieved.
+  EFI_IP_ADDRESS  SubnetAddr;                   ///< Subnet ID.
+  EFI_IP_ADDRESS  SubnetMask;                   ///< Subnet mask (IPv4 only)
+  UINT8           SubnetPrefixLength;           ///< Subnet prefix.
+  UINT16          VlanId;                       ///< VLAN ID
+  UINT32          SubnetAddrInfoIPv6Number;     ///< IPv6 address info number.
+  EFI_IP6_ADDRESS_INFO *SubnetAddrInfoIPv6;     ///< IPv6 address info.
+  //
+  // Network interface protocol and REST EX infor.
+  //
+  UINT32          NetworkProtocolType;          ///< Network protocol type. Refer to
+                                                ///< NETWORK_INTERFACE_PROTOCOL_TYPE.
+  REDFISH_DISCOVER_NETWORK_INTERFACE_PROTOCOL NetworkInterfaceProtocolInfo; ///< Network interface protocol information.
+  EFI_HANDLE      RestExHandle;                 ///< REST EX handle associated with this network interface.
+} EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL;
+
+//
+// Internal structure used to maintain REST EX properties.
+//
+typedef struct {
+    LIST_ENTRY      Entry;                          ///< Link list entry.
+    EFI_HANDLE      OpenDriverAgentHandle;          ///< The agent to open network protocol.
+    EFI_HANDLE      OpenDriverControllerHandle;     ///< The controller handle to open network protocol.
+    EFI_HANDLE      RestExChildHandle;              ///< The child handle created throught REST EX Service Protocol.
+    EFI_HANDLE      RestExControllerHandle;         ///< The controller handle which provide REST EX protocol.
+    EFI_REST_EX_PROTOCOL *RestExProtocolInterface;  ///< Pointer to EFI_REST_EX_PROTOCOL.
+    UINT32          RestExId;                       ///< The identifier installed on REST EX controller handle.
+} EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL;
+
+/**
+  This function to get subnet information.
+
+  @param[in]            ImageHandle  EFI handle with this image.
+  @param[in]            Instance  Instance of Network interface.
+  @retval EFI_STATUS    Get subnet information successfully.
+  @retval Otherwise     Fail to get subnet information.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REDFISH_DISCOVER_GET_SUBNET_INFO)(
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
+);
+
+//
+// The require network protocol matrix.
+//
+typedef struct {
+  UINT32   ProtocolType;                                ///< Network protocol type,
+                                                        ///< Refer to NETWORK_INTERFACE_PROTOCOL_TYPE.
+  CHAR16   *ProtocolName;                               ///< Protocol name.
+  EFI_GUID *RequiredProtocolGuid;                       ///< Network protocol interface GUID.
+  EFI_GUID *RequiredServiceBindingProtocolGuid;         ///< Network protocol service GUID.
+  EFI_GUID *DiscoveredProtocolGuid;                     ///< Protocol interface GUID use to install identifier.
+  EFI_REDFISH_DISCOVER_GET_SUBNET_INFO GetSubnetInfo;   ///< Function of getting subnet information.
+} REDFISH_DISCOVER_REQUIRED_PROTOCOL;
+
+//
+// Link list of Redfish discover instance.
+//
+typedef struct {
+  LIST_ENTRY  NextInstance;                             ///< Next list.
+  EFI_REDFISH_DISCOVERED_INSTANCE *Instance;            ///< Pointer to EFI_REDFISH_DISCOVERED_INSTANCE.
+} EFI_REDFISH_DISCOVERED_INTERNAL_LIST;
+
+//
+// Internal structure of Redfish discover instance.
+//
+typedef struct {
+  LIST_ENTRY  Entry;                                    ///< Link list entry.
+  EFI_HANDLE  Owner;                                    ///< The owner owns this Redfish service discovery.
+                                                        ///< It's the EFI image handle of driver uses
+                                                        ///< EFI Redfish Discover Protocol.
+  EFI_REDFISH_DISCOVER_FLAG DiscoverFlags;              ///< EFI_REDFISH_DISCOVER_FLAG
+  EFI_REDFISH_DISCOVERED_TOKEN *DiscoverToken;          ///< Token used to signal when Redfish service is discovered.
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NetworkInterface; ///< EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
+                                                                     ///< instance used to discover Redfish service.
+  //
+  // Below for Host insterface discovery.
+  //
+  BOOLEAN         HostIntfValidation;                   ///< Indicates whether to validate Redfish Host interface.
+  EFI_IP_ADDRESS  TargetIpAddress;                      ///< Target IP address reported in Redfish Host interface.
+} EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE;
+
+/**
+  The function adds a new foudn Redfish service to internal list and
+  notify clinet.
+
+  It simply frees the packet.
+
+  @param[in]  Instance              EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
+  @param[in]  RedfishVersion        Redfish version.
+  @param[in]  RedfishLocation       Redfish location.
+  @param[in]  Uuid                  Service UUID string.
+  @param[in]  Os                    OS string.
+  @param[in]  OsVer                 OS version string.
+  @param[in]  Product               Product string.
+  @param[in]  ProductVer            Product verison string.
+  @param[in]  UseHttps              Redfish service requires secured connection.
+  @retval EFI_SUCCESS               Redfish service is added to list successfully.
+
+**/
+EFI_STATUS
+AddAndSignalNewRedfishService (
+  IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
+  IN UINTN *RedfishVersion OPTIONAL,
+  IN CHAR8 *RedfishLocation OPTIONAL,
+  IN CHAR8 *Uuid  OPTIONAL,
+  IN CHAR8 *Os  OPTIONAL,
+  IN CHAR8 *OsVer  OPTIONAL,
+  IN CHAR8 *Product  OPTIONAL,
+  IN CHAR8 *ProductVer  OPTIONAL,
+  IN BOOLEAN UseHttps
+  );
+
+/**
+  The function gets information reported in Redfish Host Interface.
+
+  It simply frees the packet.
+
+  @param[in]  Smbios           SMBIOS protocol.
+  @param[out] DeviceDescriptor Pointer to REDFISH_INTERFACE_DATA.
+  @param[out] ProtocolData     Pointer to REDFISH_OVER_IP_PROTOCOL_DATA.
+
+  @retval EFI_SUCCESS    Get host interface succesfully.
+  @retval Otherwise      Fail to tet host interface.
+
+**/
+EFI_STATUS
+RedfishGetHostInterfaceProtocolData (
+  IN EFI_SMBIOS_PROTOCOL              *Smbios,
+  OUT REDFISH_INTERFACE_DATA          **DeviceDescriptor,
+  OUT REDFISH_OVER_IP_PROTOCOL_DATA   **ProtocolData
+  );
+
+extern EFI_GUID gRedfishDiscoverTcp4Instance;
+extern EFI_GUID gRedfishDiscoverTcp6Instance;
+extern EFI_GUID gRedfishDiscoverRestEXInstance;
+#endif
diff --git a/RedfishPkg/RedfishDiscoverDxe/ComponentName.c b/RedfishPkg/RedfishDiscoverDxe/ComponentName.c
new file mode 100644
index 0000000000..adad2504bc
--- /dev/null
+++ b/RedfishPkg/RedfishDiscoverDxe/ComponentName.c
@@ -0,0 +1,218 @@
+/** @file
+  Implementation of EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL protocol.
+  for EFI Refish Discover Protocol
+
+  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishDiscoverInternal.h"
+
+//
+// EFI Component Name Functions
+//
+/**
+  Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+  @param[in]  This       A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  Language   A pointer to a three-character ISO 639-2 language identifier.
+                         This is the language of the driver name that that the caller
+                         is requesting, and it must match one of the languages specified
+                         in SupportedLanguages.  The number of languages supported by a
+                         driver is up to the driver writer.
+  @param[out] DriverName A pointer to the Unicode string to return.  This Unicode string
+                         is the name of the driver specified by This in the language
+                         specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by This
+                                and the language specified by Language was returned
+                                in DriverName.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  );
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by an EFI Driver.
+
+  @param[in]  This             A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  ControllerHandle The handle of a controller that the driver specified by
+                               This is managing.  This handle specifies the controller
+                               whose name is to be returned.
+  @param[in]  ChildHandle      The handle of the child controller to retrieve the name
+                               of.  This is an optional parameter that may be NULL.  It
+                               will be NULL for device drivers.  It will also be NULL
+                               for a bus drivers that wish to retrieve the name of the
+                               bus controller.  It will not be NULL for a bus driver
+                               that wishes to retrieve the name of a child controller.
+  @param[in]  Language         A pointer to a three character ISO 639-2 language
+                               identifier.  This is the language of the controller name
+                               that the caller is requesting, and it must match one
+                               of the languages specified in SupportedLanguages.  The
+                               number of languages supported by a driver is up to the
+                               driver writer.
+  @param[out]  ControllerName  A pointer to the Unicode string to return.  This Unicode
+                               string is the name of the controller specified by
+                               ControllerHandle and ChildHandle in the language specified
+                               by Language, from the point of view of the driver specified
+                               by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user-readable name in the
+                                language specified by Language for the driver
+                                specified by This was returned in DriverName.
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently managing
+                                the controller specified by ControllerHandle and
+                                ChildHandle.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  EFI_HANDLE                    ControllerHandle,
+  IN  EFI_HANDLE                    ChildHandle        OPTIONAL,
+  IN  CHAR8                         *Language,
+  OUT CHAR16                        **ControllerName
+  );
+
+
+///
+/// Component Name Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME_PROTOCOL  gRedfishDiscoverComponentName = {
+  RedfishDiscoverComponentNameGetDriverName,
+  RedfishDiscoverComponentNameGetControllerName,
+  "eng"
+};
+
+///
+/// Component Name 2 Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME2_PROTOCOL  gRedfishDiscoverComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     RedfishDiscoverComponentNameGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) RedfishDiscoverComponentNameGetControllerName,
+  "en"
+};
+
+///
+/// Table of driver names
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_UNICODE_STRING_TABLE mRedfishDiscoverDriverNameTable[] = {
+  { "eng;en", (CHAR16 *)L"Redfish Discover UEFI Driver" },
+  { NULL, NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gRedfishDiscoverControllerNameTable = NULL;
+
+/**
+  Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+  @param[in]  This        A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  Language    A pointer to a three-character ISO 639-2 language identifier.
+                          This is the language of the driver name that that the caller
+                          is requesting, and it must match one of the languages specified
+                          in SupportedLanguages.  The number of languages supported by a
+                          driver is up to the driver writer.
+  @param[out]  DriverName A pointer to the Unicode string to return.  This Unicode string
+                          is the name of the driver specified by This in the language
+                          specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by This
+                                and the language specified by Language was returned
+                                in DriverName.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mRedfishDiscoverDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gRedfishDiscoverComponentName)
+           );
+}
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by an EFI Driver.
+
+  @param[in]  This             A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  ControllerHandle The handle of a controller that the driver specified by
+                               This is managing.  This handle specifies the controller
+                               whose name is to be returned.
+  @param[in]  ChildHandle      The handle of the child controller to retrieve the name
+                               of.  This is an optional parameter that may be NULL.  It
+                               will be NULL for device drivers.  It will also be NULL
+                               for a bus drivers that wish to retrieve the name of the
+                               bus controller.  It will not be NULL for a bus driver
+                               that wishes to retrieve the name of a child controller.
+  @param[in]  Language         A pointer to a three character ISO 639-2 language
+                               identifier.  This is the language of the controller name
+                               that the caller is requesting, and it must match one
+                               of the languages specified in SupportedLanguages.  The
+                               number of languages supported by a driver is up to the
+                              driver writer.
+  @param[out]  ControllerName  A pointer to the Unicode string to return.  This Unicode
+                               string is the name of the controller specified by
+                               ControllerHandle and ChildHandle in the language specified
+                               by Language, from the point of view of the driver specified
+                               by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user-readable name in the
+                                language specified by Language for the driver
+                                specified by This was returned in DriverName.
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently managing
+                                the controller specified by ControllerHandle and
+                                ChildHandle.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  EFI_HANDLE                    ControllerHandle,
+  IN  EFI_HANDLE                    ChildHandle        OPTIONAL,
+  IN  CHAR8                         *Language,
+  OUT CHAR16                        **ControllerName
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
new file mode 100644
index 0000000000..80d70a4679
--- /dev/null
+++ b/RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
@@ -0,0 +1,1910 @@
+/** @file
+
+  The implementation of EFI Redfidh Discover Protocol.
+
+  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishDiscoverInternal.h"
+
+LIST_ENTRY mRedfishDiscoverList;
+LIST_ENTRY mRedfishInstanceList;
+EFI_SMBIOS_PROTOCOL *mSmbios = NULL;
+
+UINTN mNumNetworkInterface = 0;
+UINTN mNumRestExInstance = 0;
+LIST_ENTRY mEfiRedfishDiscoverNetworkInterface;
+LIST_ENTRY mEfiRedfishDiscoverRestExInstance;
+
+EFI_GUID mRedfishDiscoverTcp4InstanceGuid = EFI_REDFISH_DISCOVER_TCP4_INSTANCE_GUID;
+EFI_GUID mRedfishDiscoverTcp6InstanceGuid = EFI_REDFISH_DISCOVER_TCP6_INSTANCE_GUID;
+EFI_GUID mRedfishDiscoverRestExInstanceGuid = EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_GUID;
+
+EFI_HANDLE EfiRedfishDiscoverProtocolHandle = NULL;
+
+EFI_STATUS
+EFIAPI
+Tcp4GetSubnetInfo (
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
+);
+
+EFI_STATUS
+EFIAPI
+Tcp6GetSubnetInfo (
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
+);
+
+static REDFISH_DISCOVER_REQUIRED_PROTOCOL gRequiredProtocol[] = {
+  {
+    ProtocolTypeTcp4,
+    L"TCP4 Service Binding Protocol",
+    &gEfiTcp4ProtocolGuid,
+    &gEfiTcp4ServiceBindingProtocolGuid,
+    &mRedfishDiscoverTcp4InstanceGuid,
+    Tcp4GetSubnetInfo
+  },
+  {
+    ProtocolTypeTcp6,
+    L"TCP6 Service Binding Protocol",
+    &gEfiTcp6ProtocolGuid,
+    &gEfiTcp6ServiceBindingProtocolGuid,
+    &mRedfishDiscoverTcp6InstanceGuid,
+    Tcp6GetSubnetInfo
+  },
+  {
+    ProtocolTypeRestEx,
+    L"REST EX Service Binding Protocol",
+    &gEfiRestExProtocolGuid,
+    &gEfiRestExServiceBindingProtocolGuid,
+    &mRedfishDiscoverRestExInstanceGuid,
+    NULL
+  }
+};
+
+/**
+  This function creates REST EX instance for the found Resfish service.
+  by known owner handle.
+
+  @param[in]    Instance        EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
+  @param[in]    Token           Client token.
+
+  @retval NULL  Instance not found.
+  @retval EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE The instance owned by this owner.
+
+**/
+EFI_STATUS
+CreateRestExInstance (
+  IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
+  IN EFI_REDFISH_DISCOVERED_TOKEN *Token
+  )
+{
+  EFI_STATUS Status;
+
+  Status = RestExLibCreateChild (
+            Instance->Owner,
+            FixedPcdGetBool (PcdRedfishDiscoverAccessModeInBand)? EfiRestExServiceInBandAccess: EfiRestExServiceOutOfBandAccess,
+            EfiRestExConfigHttp,
+            EfiRestExServiceRedfish,
+            &Token->DiscoverList.RedfishInstances->Information.RedfishRestExHandle
+            );
+  return Status;
+}
+
+/**
+  This function gets EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
+  by known owner handle.
+
+  @param[in]    ImageHandle             Image handle owns EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
+  @param[in]    TargetNetworkInterface  Target network interface used by this EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
+  @param[in]    DiscoverFlags           EFI_REDFISH_DISCOVER_FLAG
+
+  @retval NULL  Instance not found.
+  @retval EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE The instance owned by this owner.
+
+**/
+EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *
+GetInstanceByOwner (
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *TargetNetworkInterface,
+  IN EFI_REDFISH_DISCOVER_FLAG DiscoverFlags
+  )
+{
+  EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *ThisInstance;
+
+  if (IsListEmpty (&mRedfishDiscoverList)) {
+    return NULL;
+  }
+  ThisInstance =
+    (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)GetFirstNode (&mRedfishDiscoverList);
+  while (TRUE) {
+    if ((ThisInstance->Owner == ImageHandle) &&
+         (ThisInstance->DiscoverFlags == DiscoverFlags) &&
+         (ThisInstance->NetworkInterface == TargetNetworkInterface)) {
+      return ThisInstance;
+    }
+    if (IsNodeAtEnd (&mRedfishDiscoverList, &ThisInstance->Entry)) {
+      break;
+    }
+    ThisInstance =
+      (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)GetNextNode (&mRedfishDiscoverList, &ThisInstance->Entry);
+  };
+  return NULL;
+}
+
+/**
+  This function gets the subnet information of this TCP4 instance.
+
+  @param[in]            ImageHandle  EFI handle with this image.
+  @param[in]            Instance  Instance of Network interface.
+  @retval EFI_STATUS    Get subnet information successfully.
+  @retval Otherwise     Fail to get subnet information.
+**/
+EFI_STATUS
+EFIAPI
+Tcp4GetSubnetInfo (
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
+)
+{
+  EFI_STATUS Status;
+  EFI_TCP4_PROTOCOL *Tcp4;
+  EFI_TCP4_CONFIG_DATA Tcp4CfgData;
+  EFI_TCP4_OPTION Tcp4Option;
+  EFI_IP4_MODE_DATA IpModedata;
+  UINT8 SubnetMaskIndex;
+  UINT8 BitMask;
+  UINT8 PrefixLength;
+  BOOLEAN GotPrefixLength;
+
+  if (Instance == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  Tcp4 = (EFI_TCP4_PROTOCOL *)Instance->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
+
+  ZeroMem ((VOID *)&Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
+  ZeroMem ((VOID *)&Tcp4Option, sizeof (EFI_TCP4_OPTION));
+  // Give a local host IP address just for getting subnet information.
+  Tcp4CfgData.AccessPoint.UseDefaultAddress = TRUE;
+  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [0] = 127;
+  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [1] = 0;
+  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [2] = 0;
+  Tcp4CfgData.AccessPoint.RemoteAddress.Addr [3] = 1;
+  Tcp4CfgData.AccessPoint.RemotePort  = 80;
+  Tcp4CfgData.AccessPoint.ActiveFlag  = TRUE;
+
+  Tcp4CfgData.ControlOption = &Tcp4Option;
+  Tcp4Option.ReceiveBufferSize      = 65535;
+  Tcp4Option.SendBufferSize         = 65535;
+  Tcp4Option.MaxSynBackLog          = 5;
+  Tcp4Option.ConnectionTimeout      = 60;
+  Tcp4Option.DataRetries            = 12;
+  Tcp4Option.FinTimeout             = 2;
+  Tcp4Option.KeepAliveProbes        = 6;
+  Tcp4Option.KeepAliveTime          = 7200;
+  Tcp4Option.KeepAliveInterval      = 30;
+  Tcp4Option.EnableNagle            = TRUE;
+  Status = Tcp4->Configure (Tcp4, &Tcp4CfgData);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Can't get subnet information\n", __FUNCTION__));
+    return Status;
+  }
+  Status = Tcp4->GetModeData (Tcp4, NULL, NULL, &IpModedata, NULL, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Can't get IP mode data information\n", __FUNCTION__));
+    return Status;
+  }
+  IP4_COPY_ADDRESS (&Instance->SubnetMask, &IpModedata.ConfigData.SubnetMask);
+  Instance->SubnetAddr.v4.Addr [0] = IpModedata.ConfigData.StationAddress.Addr [0] & Instance->SubnetMask.v4.Addr [0];
+  Instance->SubnetAddr.v4.Addr [1] = IpModedata.ConfigData.StationAddress.Addr [1] & Instance->SubnetMask.v4.Addr [1];
+  Instance->SubnetAddr.v4.Addr [2] = IpModedata.ConfigData.StationAddress.Addr [2] & Instance->SubnetMask.v4.Addr [2];
+  Instance->SubnetAddr.v4.Addr [3] = IpModedata.ConfigData.StationAddress.Addr [3] & Instance->SubnetMask.v4.Addr [3];
+  //
+  // Calculate the subnet mask prefix.
+  //
+  GotPrefixLength = FALSE;
+  PrefixLength = 0;
+  SubnetMaskIndex = 0;
+  while (GotPrefixLength == FALSE && SubnetMaskIndex < 4) {
+    BitMask = 0x80;
+    while (BitMask != 0) {
+      if ((Instance->SubnetMask.v4.Addr [SubnetMaskIndex] & BitMask) != 0) {
+        PrefixLength ++;
+      } else {
+        GotPrefixLength = TRUE;
+        break;
+      }
+      BitMask = BitMask >> 1;
+    };
+    SubnetMaskIndex ++;
+  };
+  Instance->SubnetPrefixLength = PrefixLength;
+  return EFI_SUCCESS;
+}
+
+/**
+  This function gets the subnet information of this TCP6 instance.
+
+  @param[in]            ImageHandle  EFI handle with this image.
+  @param[in]            Instance  Instance of Network interface.
+  @retval EFI_STATUS    Get subnet information successfully.
+  @retval Otherwise     Fail to get subnet information.
+**/
+EFI_STATUS
+EFIAPI
+Tcp6GetSubnetInfo (
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
+)
+{
+  EFI_STATUS Status;
+  EFI_TCP6_PROTOCOL *Tcp6;
+  EFI_IP6_MODE_DATA IpModedata;
+
+  if (Instance == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  Tcp6 = (EFI_TCP6_PROTOCOL *)Instance->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
+
+  Status = Tcp6->GetModeData (Tcp6, NULL, NULL, &IpModedata, NULL, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Can't get IP mode data information\n"));
+    return Status;
+  }
+  if (IpModedata.AddressCount == 0) {
+    DEBUG ((DEBUG_INFO, "%a: No IPv6 address configured.\n"));
+  }
+  if (Instance->SubnetAddrInfoIPv6 != NULL) {
+    FreePool (Instance->SubnetAddrInfoIPv6);
+  }
+  Instance->SubnetAddrInfoIPv6 = AllocateZeroPool (IpModedata.AddressCount * sizeof (EFI_IP6_ADDRESS_INFO));
+  if (Instance->SubnetAddrInfoIPv6 == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to allocate memory fir IPv6 subnet address information\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  Instance->SubnetAddrInfoIPv6Number = IpModedata.AddressCount;
+  CopyMem (
+    (VOID *)Instance->SubnetAddrInfoIPv6,
+    (VOID *)&IpModedata.AddressList,
+    IpModedata.AddressCount * sizeof (EFI_IP6_ADDRESS_INFO)
+    );
+  FreePool (IpModedata.AddressList);
+  return EFI_SUCCESS;
+}
+
+/**
+  This function searches EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
+  instance with the given  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
+
+  @param[in] TargetNetworkInterface  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
+                                     NULL for all EFI_REDFISH_DISCOVER_NETWORK_INTERFACEs.
+
+  @retval Non-NULL  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL is returned.
+  @retval NULL      Non of EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance is returned.
+**/
+EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *
+GetTargetNetworkInterfaceInternal (
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE  *TargetNetworkInterface
+  )
+{
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
+
+  ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+  while (TRUE) {
+    if (CompareMem((VOID *)&ThisNetworkInterface->MacAddress, &TargetNetworkInterface->MacAddress, ThisNetworkInterface->HwAddressSize) == 0) {
+      return ThisNetworkInterface;
+    }
+    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
+      return NULL;
+    }
+    ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
+  };
+  return NULL;
+}
+
+/**
+  This function validate if target network interface is ready for discovering
+  Redfish service.
+
+  @param[in] TargetNetworkInterface  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
+                                     NULL for all EFI_REDFISH_DISCOVER_NETWORK_INTERFACEs.
+  @param[in] Flags                   EFI_REDFISH_DISCOVER_FLAG
+
+  @retval EFI_SUCCESS     Target network interface is ready to use.
+  @retval EFI_UNSUPPORTED Target network interface is not ready to use.
+**/
+EFI_STATUS
+ValidateTargetNetworkInterface (
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE  *TargetNetworkInterface,
+  IN EFI_REDFISH_DISCOVER_FLAG Flags
+  )
+{
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
+
+  if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface) && TargetNetworkInterface == NULL) {
+    return EFI_UNSUPPORTED;
+  }
+  if (TargetNetworkInterface == NULL) {
+    return EFI_SUCCESS; // Return EFI_SUCCESS if no network interface is specified.
+  }
+
+  ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode(&mEfiRedfishDiscoverNetworkInterface);
+  while (TRUE) {
+    if (CompareMem((VOID *)&ThisNetworkInterface->MacAddress, &TargetNetworkInterface->MacAddress, ThisNetworkInterface->HwAddressSize) == 0) {
+      break;
+    }
+    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
+      return EFI_UNSUPPORTED;
+    }
+    ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
+  };
+  if ((Flags & EFI_REDFISH_DISCOVER_SSDP) != 0) {
+    // Validate if UDP4/6 is supported on the given network interface.
+    // SSDP is not supported.
+
+    return EFI_SUCCESS;
+  }
+  if (ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle == NULL) {
+    return EFI_UNSUPPORTED; // The required protocol on this network interface is not found.
+  }
+  return EFI_SUCCESS;
+}
+/**
+  This function returns number of network interface instance.
+
+  @retval UINTN  Number of network interface instances.
+**/
+UINTN
+NumberOfNetworkInterface (VOID)
+{
+  UINTN Num;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
+
+  if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
+    return 0;
+  }
+
+  Num = 1;
+  ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+  while (TRUE) {
+    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
+      break;
+    }
+    ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
+    Num ++;
+  };
+  return Num;
+}
+
+/**
+  This function checks the  IP version supported on this
+  netwoek interface.
+
+  @param[in]    ThisNetworkInterface   EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
+
+  @retval TRUE  Is IPv6, otherwise IPv4.
+
+**/
+BOOLEAN
+CheckIsIpVersion6 (
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface
+)
+{
+  if (ThisNetworkInterface->NetworkProtocolType == ProtocolTypeTcp6) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+  This function discover Redfish service through SMBIOS host interface.
+
+  @param[in]    Instance     EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
+
+  @retval EFI_SUCCESS        Redfish service is discovered through SMBIOS Host interface.
+  @retval Others             Fail to discover Redfish service throught SMBIOS host interface
+
+**/
+EFI_STATUS
+DiscoverRedfishHostInterface (IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance)
+{
+  EFI_STATUS Status;
+  REDFISH_OVER_IP_PROTOCOL_DATA *Data;
+  REDFISH_INTERFACE_DATA  *DeviceDescriptor;
+  CHAR8 UuidStr[sizeof"00000000-0000-0000-0000-000000000000" + 1];
+  CHAR16 Ipv6Str [sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1];
+  CHAR8 RedfishServiceLocateStr [sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1];
+  UINTN StrSize;
+  UINTN MacCompareStstus;
+  BOOLEAN IsHttps;
+
+  Data = NULL;
+  DeviceDescriptor = NULL;
+
+  if (mSmbios == NULL) {
+    Status = gBS->LocateProtocol(&gEfiSmbiosProtocolGuid, NULL, (VOID **)&mSmbios);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+  Status = RedfishGetHostInterfaceProtocolData (mSmbios, &DeviceDescriptor, &Data); // Search for SMBIOS type 42h
+  if (!EFI_ERROR (Status) && Data != NULL && DeviceDescriptor != NULL) {
+    //
+    // Chceck if we can reach out Redfish service using this network interface.
+    // Check with MAC address using Device Descroptor Data Device Type 04 and Type 05.
+    // Those two types of Redfish host interface device has MAC information.
+    //
+    if (DeviceDescriptor->DeviceType == REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2) {
+      MacCompareStstus = CompareMem(&Instance->NetworkInterface->MacAddress, &DeviceDescriptor->DeviceDescriptor.PciPcieDeviceV2.MacAddress, 6);
+    } else if (DeviceDescriptor->DeviceType == REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2){
+      MacCompareStstus = CompareMem(&Instance->NetworkInterface->MacAddress, &DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.MacAddress, 6);
+    } else {
+      return EFI_UNSUPPORTED;
+    }
+    if (MacCompareStstus != 0) {
+      return EFI_UNSUPPORTED;
+    }
+
+    if (Data->RedfishServiceIpAddressFormat == 1) {
+      IP4_COPY_ADDRESS ((VOID *)&Instance->TargetIpAddress.v4, (VOID *)Data->RedfishServiceIpAddress);
+    } else {
+      IP6_COPY_ADDRESS ((VOID *)&Instance->TargetIpAddress.v6, (VOID *)Data->RedfishServiceIpAddress);
+    }
+
+    if (Instance->HostIntfValidation) {
+      DEBUG ((DEBUG_ERROR,"%a:Send UPnP unicast SSDP to validate this Redfish Host Interface is not supported.\n", __FUNCTION__));
+      Status = EFI_UNSUPPORTED;
+    } else {
+      //
+      // Add this istance to list without detial information of Redfish
+      // service.
+      //
+      IsHttps = FALSE;
+      if (Data->RedfishServiceIpPort == 443) {
+        IsHttps = TRUE;
+      }
+      StrSize = sizeof(UuidStr);
+      AsciiSPrint(UuidStr, StrSize, "%g", &Data->ServiceUuid);
+      //
+      // Generate Redfish service location string.
+      //
+      if (Data->RedfishServiceIpAddressFormat == REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP6) {
+        NetLibIp6ToStr((IPv6_ADDRESS *)&Data->RedfishServiceIpAddress, Ipv6Str, sizeof (Ipv6Str));
+        if (Data->RedfishServiceIpPort == 0 || IsHttps == TRUE) {
+            AsciiSPrintUnicodeFormat (
+              RedfishServiceLocateStr,
+              sizeof (RedfishServiceLocateStr),
+              L"%s",
+              Ipv6Str
+            );
+        } else {
+            AsciiSPrintUnicodeFormat(
+              RedfishServiceLocateStr,
+              sizeof (RedfishServiceLocateStr),
+              L"[%s]:%d",
+              Ipv6Str,
+              Data->RedfishServiceIpPort
+            );
+        }
+      } else {
+        if (Data->RedfishServiceIpPort == 0 || IsHttps == TRUE) {
+          AsciiSPrint(
+            RedfishServiceLocateStr,
+            sizeof (RedfishServiceLocateStr),
+            "%d.%d.%d.%d",
+            Data->RedfishServiceIpAddress [0],
+            Data->RedfishServiceIpAddress [1],
+            Data->RedfishServiceIpAddress [2],
+            Data->RedfishServiceIpAddress [3]
+            );
+        } else {
+          AsciiSPrint(
+            RedfishServiceLocateStr,
+            sizeof (RedfishServiceLocateStr),
+            "%d.%d.%d.%d:%d",
+            Data->RedfishServiceIpAddress [0],
+            Data->RedfishServiceIpAddress [1],
+            Data->RedfishServiceIpAddress [2],
+            Data->RedfishServiceIpAddress [3],
+            Data->RedfishServiceIpPort
+            );
+        }
+       }
+      Status = AddAndSignalNewRedfishService (
+            Instance,
+            NULL,
+            RedfishServiceLocateStr,
+            UuidStr,
+            NULL,
+            NULL,
+            NULL,
+            NULL,
+            IsHttps
+            );
+    }
+  }
+  return Status;
+}
+
+/**
+  The function adds a new found Redfish service to internal list and
+  notify client.
+
+  @param[in]  Instance              EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
+  @param[in]  RedfishVersion        Redfish version.
+  @param[in]  RedfishLocation       Redfish location.
+  @param[in]  Uuid                  Service UUID string.
+  @param[in]  Os                    OS string.
+  @param[in]  OsVer                 OS version string.
+  @param[in]  Product               Product string.
+  @param[in]  ProductVer            Product verison string.
+  @param[in]  UseHttps              Redfish service requires secured connection.
+  @retval EFI_SUCCESS               Redfish service is added to list successfully.
+
+**/
+EFI_STATUS
+AddAndSignalNewRedfishService (
+  IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
+  IN UINTN *RedfishVersion OPTIONAL,
+  IN CHAR8 *RedfishLocation OPTIONAL,
+  IN CHAR8 *Uuid  OPTIONAL,
+  IN CHAR8 *Os  OPTIONAL,
+  IN CHAR8 *OsVer  OPTIONAL,
+  IN CHAR8 *Product  OPTIONAL,
+  IN CHAR8 *ProductVer  OPTIONAL,
+  IN BOOLEAN UseHttps
+  )
+{
+  BOOLEAN NewFound;
+  BOOLEAN InfoRefresh;
+  BOOLEAN RestExOpened;
+  BOOLEAN DeleteRestEx;
+  EFI_STATUS Status;
+  EFI_REDFISH_DISCOVERED_INTERNAL_LIST *DiscoveredList;
+  EFI_REDFISH_DISCOVERED_INSTANCE *DiscoveredInstance;
+  CHAR16 *Char16Uuid;
+  EFI_REST_EX_PROTOCOL *RestEx;
+  EFI_REST_EX_HTTP_CONFIG_DATA *RestExHttpConfigData;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NetworkInterface;
+
+  NewFound = TRUE;
+  InfoRefresh = FALSE;
+  Char16Uuid = NULL;
+  RestExOpened = FALSE;
+  DeleteRestEx = FALSE;
+
+  DEBUG ((DEBUG_INFO,"%a:Add this instance to Redfish instance list.\n", __FUNCTION__));
+
+  if (Uuid != NULL) {
+    Char16Uuid = (CHAR16 *)AllocateZeroPool(AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
+    AsciiStrToUnicodeStrS ((const CHAR8 *)Uuid, Char16Uuid, AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
+  }
+  DiscoveredList = NULL;
+  DiscoveredInstance = NULL;
+  RestExHttpConfigData = NULL;
+
+  NetworkInterface = Instance->NetworkInterface;
+  if (!IsListEmpty (&mRedfishInstanceList)) {
+    //
+    // Is this a duplicate redfish service.
+    //
+    DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetFirstNode (&mRedfishInstanceList);
+    NewFound = FALSE;
+    do {
+      if (Char16Uuid == NULL || DiscoveredList->Instance->Information.Uuid == NULL) {
+        //
+        // Check if this Redfish instance already found using IP addrress.
+        //
+        if (!CheckIsIpVersion6(NetworkInterface)) {
+          if (CompareMem ((VOID *)&Instance->TargetIpAddress.v4,
+                      (VOID *)&DiscoveredList->Instance->Information.RedfishHostIpAddress.v4,
+                      sizeof (EFI_IPv4_ADDRESS)
+                      ) == 0)
+          {
+            DiscoveredInstance = DiscoveredList->Instance;
+            if (DiscoveredList->Instance->Information.Uuid == NULL &&
+                Char16Uuid != NULL) {
+              InfoRefresh = TRUE;
+              DiscoveredInstance = DiscoveredList->Instance;
+              DEBUG((DEBUG_INFO,"*** This Redfish Service information refresh ***\n"));
+            }
+            break;
+          }
+        } else {
+          if (CompareMem ((VOID *)&Instance->TargetIpAddress.v6,
+                      (VOID *)&DiscoveredList->Instance->Information.RedfishHostIpAddress.v6,
+                      sizeof (EFI_IPv6_ADDRESS)
+                      ) == 0)
+          {
+            DiscoveredInstance = DiscoveredList->Instance;
+            break;
+          }
+        }
+      } else {
+        //
+        // Check if this Redfish instance already found using UUID.
+        //
+        if (StrCmp((const CHAR16 *)Char16Uuid, (const CHAR16 *)DiscoveredList->Instance->Information.Uuid) == 0) {
+          DiscoveredInstance = DiscoveredList->Instance;
+          break;
+        }
+      }
+      if (IsNodeAtEnd (&mRedfishInstanceList, &DiscoveredList->NextInstance)) {
+        NewFound = TRUE;
+        break;
+      }
+      DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetNextNode (&mRedfishInstanceList, &DiscoveredList->NextInstance);
+    } while (TRUE);
+  }
+  if (NewFound || InfoRefresh) {
+    if (!InfoRefresh) {
+      DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INTERNAL_LIST));
+      if (DiscoveredList == NULL) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+      InitializeListHead (&DiscoveredList->NextInstance);
+      DiscoveredInstance = (EFI_REDFISH_DISCOVERED_INSTANCE *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INSTANCE));
+      if (DiscoveredInstance == NULL) {
+        FreePool ((VOID *)DiscoveredList);
+        return EFI_OUT_OF_RESOURCES;
+      }
+    }
+    DEBUG ((DEBUG_INFO,"*** Redfish Service Information ***\n"));
+
+    DiscoveredInstance->Information.UseHttps = UseHttps;
+    if (RedfishVersion != NULL) {
+      DiscoveredInstance->Information.RedfishVersion = *RedfishVersion;
+      DEBUG ((DEBUG_INFO,"Redfish service version: %d.\n", DiscoveredInstance->Information.RedfishVersion));
+    }
+    if (RedfishLocation != NULL) {
+      DiscoveredInstance->Information.Location = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)RedfishLocation) * sizeof(CHAR16));
+      AsciiStrToUnicodeStrS ((const CHAR8 *)RedfishLocation, DiscoveredInstance->Information.Location, AsciiStrSize((const CHAR8 *)RedfishLocation) * sizeof(CHAR16));
+      DEBUG ((DEBUG_INFO,"Redfish service location: %s.\n", DiscoveredInstance->Information.Location));
+    }
+    if (Uuid != NULL) {
+      DiscoveredInstance->Information.Uuid = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
+      AsciiStrToUnicodeStrS ((const CHAR8 *)Uuid, DiscoveredInstance->Information.Uuid, AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
+      DEBUG ((DEBUG_INFO,"Service UUID: %s.\n", DiscoveredInstance->Information.Uuid));
+    }
+    if (Os != NULL) {
+      DiscoveredInstance->Information.Os = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)Os) * sizeof(CHAR16));
+      AsciiStrToUnicodeStrS ((const CHAR8 *)Os, DiscoveredInstance->Information.Os, AsciiStrSize((const CHAR8 *)Os) * sizeof(CHAR16));
+      DEBUG ((DEBUG_INFO,"Redfish service OS: %s, Version:%s.\n", DiscoveredInstance->Information.Os, DiscoveredInstance->Information.OsVersion));
+    }
+    if (OsVer != NULL) {
+      DiscoveredInstance->Information.OsVersion = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)OsVer) * sizeof(CHAR16));
+      AsciiStrToUnicodeStrS ((const CHAR8 *)OsVer, DiscoveredInstance->Information.OsVersion, AsciiStrSize((const CHAR8 *)OsVer) * sizeof(CHAR16));
+    }
+    if (Product != NULL && ProductVer != NULL) {
+      DiscoveredInstance->Information.Product = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)Product) * sizeof(CHAR16));
+      AsciiStrToUnicodeStrS ((const CHAR8 *)Product, DiscoveredInstance->Information.Product, AsciiStrSize((const CHAR8 *)Product) * sizeof(CHAR16));
+      DiscoveredInstance->Information.ProductVer = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)ProductVer) * sizeof(CHAR16));
+      AsciiStrToUnicodeStrS ((const CHAR8 *)ProductVer, DiscoveredInstance->Information.ProductVer, AsciiStrSize((const CHAR8 *)ProductVer) * sizeof(CHAR16));
+      DEBUG ((DEBUG_INFO,"Redfish service product: %s, Version:%s.\n", DiscoveredInstance->Information.Product, DiscoveredInstance->Information.ProductVer));
+    }
+
+    if (RedfishLocation == NULL) {
+      // This is the Redfish reported from SMBIOS 42h
+      // without validation.
+
+      IP4_COPY_ADDRESS((VOID *)&DiscoveredInstance->Information.RedfishHostIpAddress.v4, (VOID *)&Instance->TargetIpAddress.v4);
+    }
+    if (!InfoRefresh) {
+      DiscoveredList->Instance = DiscoveredInstance;
+      InsertTailList(&mRedfishInstanceList, &DiscoveredList->NextInstance);
+    }
+    DiscoveredInstance->Status = EFI_SUCCESS;
+  } else {
+    if (DiscoveredList != NULL) {
+      DEBUG((DEBUG_INFO,"*** This Redfish Service was already found ***\n"));
+      if (DiscoveredInstance->Information.Uuid != NULL) {
+        DEBUG((DEBUG_INFO,"Service UUID: %s.\n", DiscoveredInstance->Information.Uuid));
+      } else {
+        DEBUG((DEBUG_INFO,"Service UUID: unknown.\n"));
+      }
+    }
+  }
+  if (Char16Uuid != NULL) {
+    FreePool((VOID *)Char16Uuid);
+  }
+
+  Status = EFI_SUCCESS;
+  if (NewFound || InfoRefresh) {
+    //
+    // Build up EFI_REDFISH_DISCOVERED_LIST in token.
+    //
+    Instance->DiscoverToken->DiscoverList.NumberOfServiceFound = 1;
+    Instance->DiscoverToken->DiscoverList.RedfishInstances = DiscoveredInstance;
+    DiscoveredInstance->Status = EFI_SUCCESS;
+    if (!InfoRefresh) {
+      Status = CreateRestExInstance (Instance, Instance->DiscoverToken); // Create REST EX child.
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a:Can't create REST EX child instance.\n",__FUNCTION__));
+        goto ON_EXIT;
+      }
+      Status = gBS->OpenProtocol ( // Configure local host information.
+                  Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
+                  &gEfiRestExProtocolGuid,
+                  (VOID **)&RestEx,
+                  Instance->NetworkInterface->OpenDriverAgentHandle,
+                  Instance->NetworkInterface->OpenDriverControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+      if (EFI_ERROR (Status)) {
+        DeleteRestEx = TRUE;
+        goto ERROR_EXIT;
+      }
+      RestExOpened = TRUE;
+      RestExHttpConfigData = AllocateZeroPool (sizeof (EFI_REST_EX_HTTP_CONFIG_DATA));
+      if (RestExHttpConfigData == NULL) {
+        Status = EFI_OUT_OF_RESOURCES;
+        DeleteRestEx = TRUE;
+        goto EXIT_FREE_CONFIG_DATA;
+      }
+      RestExHttpConfigData->SendReceiveTimeout = 5000;
+      RestExHttpConfigData->HttpConfigData.HttpVersion = HttpVersion11;
+      RestExHttpConfigData->HttpConfigData.LocalAddressIsIPv6 = CheckIsIpVersion6(NetworkInterface);
+      if (RestExHttpConfigData->HttpConfigData.LocalAddressIsIPv6) {
+        RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node = AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT));
+        if (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node == NULL) {
+          Status = EFI_OUT_OF_RESOURCES;
+          goto EXIT_FREE_CONFIG_DATA;
+        }
+      } else {
+        RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node = AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT));
+        if (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node == NULL) {
+          Status = EFI_OUT_OF_RESOURCES;
+          goto EXIT_FREE_CONFIG_DATA;
+        }
+        RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node->UseDefaultAddress = TRUE;
+      }
+      Status = RestEx->Configure (
+                       RestEx,
+                       (EFI_REST_EX_CONFIG_DATA)(UINT8 *)RestExHttpConfigData
+                       );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR,"%a:REST EX configured..\n", __FUNCTION__));
+        DeleteRestEx = TRUE;
+        goto EXIT_FREE_ALL;
+      }
+      //
+      // Signal client, close REST EX before signaling client.
+      //
+      if (RestExOpened) {
+        gBS->CloseProtocol(
+             Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
+             &gEfiRestExProtocolGuid,
+             Instance->NetworkInterface->OpenDriverAgentHandle,
+             Instance->NetworkInterface->OpenDriverControllerHandle
+          );
+        RestExOpened = FALSE;
+      }
+    }
+    Status = gBS->SignalEvent(Instance->DiscoverToken->Event);
+    if (!EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR,"%a:No event to signal!\n", __FUNCTION__));
+    }
+  }
+
+EXIT_FREE_ALL:;
+  if (RestExHttpConfigData != NULL && RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node != NULL) {
+    FreePool (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node);
+  }
+
+EXIT_FREE_CONFIG_DATA:;
+  if (RestExHttpConfigData != NULL) {
+    FreePool((VOID *)RestExHttpConfigData);
+  }
+  if (RestExOpened) {
+    gBS->CloseProtocol(
+           Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
+           &gEfiRestExProtocolGuid,
+           Instance->NetworkInterface->OpenDriverAgentHandle,
+           Instance->NetworkInterface->OpenDriverControllerHandle
+        );
+  }
+ERROR_EXIT:;
+    if (DeleteRestEx && RestExOpened) {
+      gBS->CloseProtocol(
+           Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
+           &gEfiRestExProtocolGuid,
+           Instance->NetworkInterface->OpenDriverAgentHandle,
+           Instance->NetworkInterface->OpenDriverControllerHandle
+        );
+    }
+ON_EXIT:;
+  return Status;
+}
+
+/**
+  This function gets the subnet information of this network interface instance.
+  can discover Redfish service on it.
+
+  @param[in]    Instance     EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance.
+  @param[in]    ImageHandle  EFI Image handle request the network interface list.
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+NetworkInterfaceGetSubnetInfo (
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance,
+  IN EFI_HANDLE ImageHandle
+  )
+{
+  EFI_STATUS Status;
+  UINT32 ProtocolType;
+  UINT32 IPv6InfoIndex;
+  EFI_IP6_ADDRESS_INFO *ThisSubnetAddrInfoIPv6;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NewNetworkInterface;
+
+  if (Instance->GotSubnetInfo) {
+    return EFI_SUCCESS;
+  }
+
+  ProtocolType = Instance->NetworkProtocolType;
+  if (gRequiredProtocol [ProtocolType].GetSubnetInfo != NULL && Instance->GotSubnetInfo == FALSE) {
+    Status = gRequiredProtocol [ProtocolType].GetSubnetInfo (
+        ImageHandle,
+        Instance
+        );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR,"%a:Faile to get Subnet infomation.\n", __FUNCTION__));
+      return Status;
+    } else {
+      DEBUG ((DEBUG_INFO,"%a:MAC address: %s\n", __FUNCTION__, Instance->StrMacAddr));
+      if (CheckIsIpVersion6 (Instance)) {
+        if (Instance->SubnetAddrInfoIPv6Number == 0) {
+          DEBUG ((DEBUG_ERROR,"%a: There is no Subnet infomation for IPv6 network interface.\n", __FUNCTION__));
+          return EFI_NOT_FOUND;
+        }
+        ThisSubnetAddrInfoIPv6 = Instance->SubnetAddrInfoIPv6; // First IPv6 address information.
+        IP6_COPY_ADDRESS (&Instance->SubnetAddr.v6, &ThisSubnetAddrInfoIPv6->Address);
+        Instance->SubnetPrefixLength = ThisSubnetAddrInfoIPv6->PrefixLength;
+        DEBUG((DEBUG_INFO,"   IPv6 Subnet ID:%d, Prefix length: %d.\n",
+               ThisSubnetAddrInfoIPv6->Address.Addr [7] + (UINT16)ThisSubnetAddrInfoIPv6->Address.Addr [6] * 256,
+               ThisSubnetAddrInfoIPv6->PrefixLength)
+               );
+        //
+        // If this is IPv6, then we may have to propagate network interface for IPv6 network scopes
+        // according to the Ipv6 address information.
+        //
+        ThisSubnetAddrInfoIPv6 ++;
+        for (IPv6InfoIndex = 0; IPv6InfoIndex < Instance->SubnetAddrInfoIPv6Number - 1; IPv6InfoIndex++) {
+          //
+          // Build up addtional EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instances.
+          //
+          NewNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL));
+          if (NewNetworkInterface != NULL) {
+            CopyMem ((VOID *)NewNetworkInterface, (VOID *)Instance, sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL)); // Clone information of first instance.
+            IP6_COPY_ADDRESS (&NewNetworkInterface->SubnetAddr.v6, &ThisSubnetAddrInfoIPv6->Address);
+            NewNetworkInterface->SubnetPrefixLength = ThisSubnetAddrInfoIPv6->PrefixLength;
+            NewNetworkInterface->GotSubnetInfo = TRUE;
+            InsertTailList (&mEfiRedfishDiscoverNetworkInterface, &NewNetworkInterface->Entry);
+            ThisSubnetAddrInfoIPv6 ++;
+            mNumNetworkInterface ++;
+            DEBUG((DEBUG_INFO,"   IPv6 Subnet ID:%d, Prefix length: %d.\n",
+                   ThisSubnetAddrInfoIPv6->Address.Addr [7] + (UINT16)ThisSubnetAddrInfoIPv6->Address.Addr [6] * 256,
+                   ThisSubnetAddrInfoIPv6->PrefixLength)
+                  );
+          } else {
+            return EFI_OUT_OF_RESOURCES;
+          }
+        }
+      } else {
+        DEBUG ((DEBUG_INFO,"   IPv4 Subnet:%d.%d.%d.%d Subnet mask: %d.%d.%d.%d.\n",
+                    Instance->SubnetAddr.v4.Addr [0],
+                    Instance->SubnetAddr.v4.Addr [1],
+                    Instance->SubnetAddr.v4.Addr [2],
+                    Instance->SubnetAddr.v4.Addr [3],
+                    Instance->SubnetMask.v4.Addr [0],
+                    Instance->SubnetMask.v4.Addr [1],
+                    Instance->SubnetMask.v4.Addr [2],
+                    Instance->SubnetMask.v4.Addr [3]
+                    ));
+      }
+    }
+  }
+  Instance->GotSubnetInfo = TRUE; // Only try to get Subnet Info once.
+  return EFI_SUCCESS;
+}
+
+/**
+  This function gets the network interface list which Redfish discover protocol
+  can discover Redfish service on it.
+
+  @param[in]    This                  EFI_REDFISH_DISCOVER_PROTOCOL instance.
+  @param[in]    ImageHandle           EFI Image handle request the network interface list,
+  @param[out]   NumberOfNetworkIntfs  Number of network interfaces can do Redfish service discovery.
+  @param[out]   NetworkIntfInstances  Network interface instances. It's an array of instance. The number of entries
+                                      in array is indicated by NumberOfNetworkIntfs.
+                                      Caller has to release the memory
+                                      allocated by Redfish discover protocol.
+
+  @retval EFI_SUCCESS        The information of network interface is returned in NumberOfNetworkIntfs and
+                             NetworkIntfInstances.
+  @retval Others             Fail to return the information of network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishServiceGetNetworkInterface (
+  IN EFI_REDFISH_DISCOVER_PROTOCOL   *This,
+  IN EFI_HANDLE                      ImageHandle,
+  OUT UINTN                          *NumberOfNetworkIntfs,
+  OUT EFI_REDFISH_DISCOVER_NETWORK_INTERFACE **NetworkIntfInstances
+)
+{
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterfaceIntn;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *ThisNetworkInterface;
+
+  if (NetworkIntfInstances == NULL || NumberOfNetworkIntfs == NULL || ImageHandle == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *NumberOfNetworkIntfs = 0;
+  *NetworkIntfInstances = NULL;
+
+  if (IsListEmpty ((const LIST_ENTRY*)&mEfiRedfishDiscoverNetworkInterface)) {
+    return EFI_NOT_FOUND;
+  }
+
+  ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE) * mNumNetworkInterface);
+  if (ThisNetworkInterface == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  *NetworkIntfInstances = ThisNetworkInterface;
+  ThisNetworkInterfaceIntn = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+  while (TRUE) {
+    ThisNetworkInterface->IsIpv6 = FALSE;
+    if (CheckIsIpVersion6 (ThisNetworkInterfaceIntn)) {
+      ThisNetworkInterface->IsIpv6 = TRUE;
+    }
+    CopyMem((VOID *)&ThisNetworkInterface->MacAddress, &ThisNetworkInterfaceIntn->MacAddress, ThisNetworkInterfaceIntn->HwAddressSize);
+    NetworkInterfaceGetSubnetInfo(ThisNetworkInterfaceIntn, ImageHandle); // Get subnet info.
+    if (!ThisNetworkInterface->IsIpv6) {
+      IP4_COPY_ADDRESS(&ThisNetworkInterface->SubnetId.v4, &ThisNetworkInterfaceIntn->SubnetAddr.v4); // IPv4 subnet information.
+    } else {
+      IP6_COPY_ADDRESS (&ThisNetworkInterface->SubnetId.v6, &ThisNetworkInterfaceIntn->SubnetAddr.v6); // IPv6 subnet information in IPv6 address information.
+    }
+    ThisNetworkInterface->SubnetPrefixLength = ThisNetworkInterfaceIntn->SubnetPrefixLength;
+    ThisNetworkInterface->VlanId = ThisNetworkInterfaceIntn->VlanId;
+    (*NumberOfNetworkIntfs) ++;
+    if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterfaceIntn->Entry)) {
+      break;
+    }
+    ThisNetworkInterfaceIntn = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterfaceIntn->Entry);
+    ThisNetworkInterface ++;
+  };
+  return EFI_SUCCESS;
+}
+/**
+  This function acquires Redfish services by discovering static Redfish setting
+  according to Redfish Host Interface or through SSDP. Returns a list of EFI
+  handles in EFI_REDFISH_DISCOVERED_LIST. Each of EFI handle has cooresponding
+  EFI REST EX instance installed on it. Each REST EX isntance is a child instance which
+  created through EFI REST EX serivce protoocl for communicating with specific
+  Redfish service.
+
+  @param[in]    This                    EFI_REDFISH_DISCOVER_PROTOCOL instance.
+  @param[in]    ImageHandle             EFI image owns these Redfish service instances.
+  @param[in]    TargetNetworkInterface  Target network interface to do the discovery.
+                                        NULL means discover Redfish service on all network interfaces on platform.
+  @param[in]    Flags                   Redfish service discover flags.
+  @param[in]    Token                   EFI_REDFISH_DISCOVERED_TOKEN instance.
+                                        The memory of EFI_REDFISH_DISCOVERED_LIST and the strings in
+                                        EFI_REDFISH_DISCOVERED_INFORMATION are all allocated by Acquire()
+                                        and must be freed when caller invoke Release().
+
+  @retval EFI_SUCCESS             REST EX instance of discovered Redfish services are returned.
+  @retval EFI_INVALID_PARAMETERS  ImageHandle == NULL, Flags == 0, Token == NULL, Token->Timeout > 5,
+                                  or Token->Event == NULL.
+  @retval Others                  Fail acquire Redfish services.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishServiceAcquireService (
+  IN EFI_REDFISH_DISCOVER_PROTOCOL          *This,
+  IN EFI_HANDLE                             ImageHandle,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE  *TargetNetworkInterface,
+  IN EFI_REDFISH_DISCOVER_FLAG              Flags,
+  IN EFI_REDFISH_DISCOVERED_TOKEN           *Token
+  )
+{
+  EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance;
+  EFI_STATUS Status1;
+  EFI_STATUS Status2;
+  BOOLEAN NewInstance;
+  UINTN NumNetworkInterfaces;
+  UINTN NetworkInterfacesIndex;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *TargetNetworkInterfaceInternal;
+
+  DEBUG ((DEBUG_INFO,"%a:Entry.\n", __FUNCTION__));
+
+  //
+  // Validate parameters.
+  //
+  if (ImageHandle == NULL || Token == NULL || ((Flags & ~EFI_REDFISH_DISCOVER_VALIDATION) == 0)) {
+    DEBUG ((DEBUG_ERROR,"%a:Invalid parameters.\n", __FUNCTION__));
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Validate target network interface.
+  //
+  if (EFI_ERROR (ValidateTargetNetworkInterface (TargetNetworkInterface, Flags))) {
+      return EFI_UNSUPPORTED;
+  }
+  if (TargetNetworkInterface != NULL) {
+    TargetNetworkInterfaceInternal = GetTargetNetworkInterfaceInternal (TargetNetworkInterface);
+    NumNetworkInterfaces = 1;
+  } else {
+    TargetNetworkInterfaceInternal = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+    NumNetworkInterfaces = NumberOfNetworkInterface ();
+    if (NumNetworkInterfaces == 0) {
+      DEBUG ((DEBUG_ERROR,"%a:No network interface on platform.\n", __FUNCTION__));
+      return EFI_UNSUPPORTED;
+    }
+  }
+  for (NetworkInterfacesIndex = 0; NetworkInterfacesIndex < NumNetworkInterfaces; NetworkInterfacesIndex ++) {
+    Status1 = EFI_SUCCESS;
+    Status2 = EFI_SUCCESS;
+    NewInstance = FALSE;
+    Instance = GetInstanceByOwner (ImageHandle, TargetNetworkInterfaceInternal, Flags & ~EFI_REDFISH_DISCOVER_VALIDATION); // Check if we can re-use previous instance.
+    if (Instance == NULL) {
+      DEBUG ((DEBUG_INFO,"%a:Create new EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.\n", __FUNCTION__));
+      Instance = (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE));
+      if (Instance == NULL) {
+        DEBUG ((DEBUG_ERROR,"%a:Memory allocation fail.\n", __FUNCTION__));
+      }
+      InitializeListHead (&Instance->Entry);
+      Instance->Owner = ImageHandle;
+      Instance->DiscoverFlags = Flags & ~EFI_REDFISH_DISCOVER_VALIDATION;
+      Instance->NetworkInterface = TargetNetworkInterfaceInternal;
+      //
+      // Get subnet information in case subnet information is not set because
+      // RedfishServiceGetNetworkInterfaces hasn't been called yet.
+      //
+      NetworkInterfaceGetSubnetInfo (TargetNetworkInterfaceInternal, ImageHandle);
+      NewInstance = TRUE;
+    }
+    if (TargetNetworkInterfaceInternal->StrMacAddr != NULL) {
+      DEBUG((DEBUG_INFO,"%a:Acquire Redfish service on network interface MAC address:%s.\n", __FUNCTION__, TargetNetworkInterfaceInternal->StrMacAddr));
+    } else {
+      DEBUG((DEBUG_INFO,"%a:WARNING: No MAC address on this network interface.\n", __FUNCTION__));
+    }
+
+    Instance->DiscoverToken = Token; // Always use the latest Token passed by caller.
+    if ((Flags & EFI_REDFISH_DISCOVER_HOST_INTERFACE) != 0) {
+      DEBUG ((DEBUG_INFO,"%a:Redfish HOST interface discovery.\n", __FUNCTION__));
+      Instance->HostIntfValidation = FALSE;
+      if ((Flags & EFI_REDFISH_DISCOVER_VALIDATION) != 0) {
+        Instance->HostIntfValidation = TRUE;
+      }
+      Status1 = DiscoverRedfishHostInterface (Instance); // Discover Redfish service through Redfish Host Interface.
+    }
+    if ((Flags & EFI_REDFISH_DISCOVER_SSDP) != 0) {
+      DEBUG ((DEBUG_ERROR,"%a:Redfish service discovery through SSDP is not supported\n", __FUNCTION__));
+      return EFI_UNSUPPORTED;
+    } else {
+      if (EFI_ERROR (Status1) && EFI_ERROR (Status2)) {
+        FreePool ((VOID *)Instance);
+        DEBUG ((DEBUG_ERROR,"%a:Something wrong on Redfish service discovery Status1=%x, Status2=%x.\n", __FUNCTION__, Status1, Status2));
+      } else {
+        if (NewInstance) {
+          InsertTailList(&mRedfishDiscoverList, &Instance->Entry);
+        }
+      }
+    }
+    if (TargetNetworkInterface == NULL) {
+      //
+      // Discover Redfish services on all of network interfaces.
+      //
+      TargetNetworkInterfaceInternal = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &TargetNetworkInterfaceInternal->Entry);
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  This function aborts Redfish service discovery on the given network interface.
+
+  @param[in]    This                    EFI_REDFISH_DISCOVER_PROTOCOL instance.
+  @param[in]    TargetNetworkInterface  Target network interface to do the discovery.
+
+  @retval EFI_SUCCESS             REST EX instance of discovered Redfish services are returned.
+  @retval Others                  Fail to abort Redfish service discovery.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishServiceAbortAcquire (
+  IN EFI_REDFISH_DISCOVER_PROTOCOL      *This,
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE  *TargetNetworkInterface OPTIONAL
+)
+{
+  // This function is used to abort Redfish service discovery through SSDP
+  // on the network interface. SSDP is optionally supprted by EFI_REDFISH_DISCOVER_PROTOCOL,
+  // we dont have implementation for SSDP now.
+
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  This function releases Redfish services found by RedfishServiceAcquire().
+
+  @param[in]    This         EFI_REDFISH_DISCOVER_PROTOCOL instance.
+  @param[in]    InstanceList The Redfish service to release.
+
+  @retval EFI_SUCCESS        REST EX instances of discovered Redfish are released.
+  @retval Others             Fail to remove the entry
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishServiceReleaseService (
+  IN EFI_REDFISH_DISCOVER_PROTOCOL   *This,
+  IN EFI_REDFISH_DISCOVERED_LIST *InstanceList
+  )
+{
+  UINTN NumService;
+  BOOLEAN AnyFailRelease;
+  EFI_REDFISH_DISCOVERED_INSTANCE *ThisRedfishInstance;
+  EFI_REDFISH_DISCOVERED_INTERNAL_LIST *DiscoveredRedfishInstance;
+
+  if (IsListEmpty (&mRedfishInstanceList)) {
+    DEBUG ((DEBUG_ERROR,"%a:No any discovered Redfish service.\n", __FUNCTION__));
+    return EFI_NOT_FOUND;
+  }
+  AnyFailRelease = FALSE;
+  ThisRedfishInstance = InstanceList->RedfishInstances;
+  for (NumService = 0; NumService < InstanceList->NumberOfServiceFound; NumService ++) {
+    DiscoveredRedfishInstance = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetFirstNode(&mRedfishInstanceList);
+    do {
+      if (DiscoveredRedfishInstance->Instance == ThisRedfishInstance) {
+        RemoveEntryList (&DiscoveredRedfishInstance->NextInstance);
+        if (ThisRedfishInstance->Information.Location != NULL) {
+          FreePool (ThisRedfishInstance->Information.Location);
+        }
+        if (ThisRedfishInstance->Information.Uuid != NULL) {
+          FreePool (ThisRedfishInstance->Information.Uuid);
+        }
+        if (ThisRedfishInstance->Information.Os != NULL) {
+          FreePool (ThisRedfishInstance->Information.Os);
+        }
+        if (ThisRedfishInstance->Information.OsVersion != NULL) {
+          FreePool (ThisRedfishInstance->Information.OsVersion);
+        }
+        if (ThisRedfishInstance->Information.Product != NULL) {
+          FreePool (ThisRedfishInstance->Information.Product);
+        }
+        if (ThisRedfishInstance->Information.ProductVer != NULL) {
+          FreePool (ThisRedfishInstance->Information.ProductVer);
+        }
+        FreePool((VOID *)ThisRedfishInstance);
+        goto ReleaseNext;
+      }
+
+      if (IsNodeAtEnd(&mRedfishInstanceList, &DiscoveredRedfishInstance->NextInstance)) {
+        break;
+      }
+      DiscoveredRedfishInstance = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetNextNode(&mRedfishInstanceList, &DiscoveredRedfishInstance->NextInstance);
+    } while (TRUE);
+    AnyFailRelease = TRUE;
+ReleaseNext:;
+    //
+    // Release next discovered Redfish Service.
+    //
+    ThisRedfishInstance = (EFI_REDFISH_DISCOVERED_INSTANCE *)((UINT8 *)ThisRedfishInstance + sizeof (EFI_REDFISH_DISCOVERED_INSTANCE));
+  }
+  if (AnyFailRelease) {
+    return EFI_NOT_FOUND;
+  } else {
+    return EFI_SUCCESS;
+  }
+}
+
+EFI_REDFISH_DISCOVER_PROTOCOL mRedfishDiscover = {
+  RedfishServiceGetNetworkInterface,
+  RedfishServiceAcquireService,
+  RedfishServiceAbortAcquire,
+  RedfishServiceReleaseService
+};
+
+/**
+  This function create an EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL for the
+  given network interface.
+
+
+  @param[in]  ControllerHandle    MAC address of this network interface.
+  @param[in]  NetworkProtocolType Network protocol type.
+  @param[out] IsNewInstance       BOOLEAN means new instance or not.
+  @param[out] NetworkInterface    Pointer to to EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL.
+
+  @retval EFI_STATUS
+**/
+EFI_STATUS
+CreateRedfishDiscoverNetworkInterface (
+  IN EFI_HANDLE ControllerHandle,
+  IN UINT32 NetworkProtocolType,
+  OUT BOOLEAN  *IsNewInstance,
+  OUT EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL **NetworkInterface
+  )
+{
+  EFI_MAC_ADDRESS MacAddress;
+  UINTN HwAddressSize;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NewNetworkInterface;
+
+  NetLibGetMacAddress (ControllerHandle, &MacAddress, &HwAddressSize);
+  NewNetworkInterface = NULL;
+  *IsNewInstance = TRUE;
+  if (!IsListEmpty ((const LIST_ENTRY*)&mEfiRedfishDiscoverNetworkInterface)) {
+    //
+    // Check if this instance already exist.
+    //
+    ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+    if (ThisNetworkInterface != NULL) {
+      while (TRUE) {
+        if ((CompareMem ((CONST VOID *)&ThisNetworkInterface->MacAddress.Addr, (CONST VOID *)&MacAddress.Addr, HwAddressSize) == 0) &&
+             (ThisNetworkInterface->NetworkProtocolType == NetworkProtocolType)){
+          NewNetworkInterface = ThisNetworkInterface;
+          *IsNewInstance = FALSE;
+          break;
+        }
+        if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
+          NewNetworkInterface = NULL;
+          break;
+        }
+        ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
+      };
+    }
+  }
+  if (NewNetworkInterface == NULL) {
+    //
+    // Create a new instance.
+    //
+    NewNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL));
+    if (NewNetworkInterface == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    NewNetworkInterface->HwAddressSize = HwAddressSize;
+    CopyMem (&NewNetworkInterface->MacAddress.Addr, &MacAddress.Addr, NewNetworkInterface->HwAddressSize);
+    NetLibGetMacString (ControllerHandle, NULL, &NewNetworkInterface->StrMacAddr);
+    NewNetworkInterface->VlanId = NetLibGetVlanId (ControllerHandle);
+  }
+  *NetworkInterface = NewNetworkInterface;
+  return EFI_SUCCESS;
+}
+
+/**
+  This function destory network interface
+
+
+  @param[in]  ThisNetworkInterface EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance.
+
+  @retval EFI_STATUS
+**/
+EFI_STATUS
+DestroyRedfishNetwrokInterface (
+  IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface
+  )
+{
+  EFI_STATUS Status;
+
+  Status = gBS->UninstallProtocolInterface(
+                  ThisNetworkInterface->OpenDriverControllerHandle,
+                  gRequiredProtocol [ThisNetworkInterface->NetworkProtocolType].DiscoveredProtocolGuid,
+                  &ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolDiscoverId
+                  );
+  RemoveEntryList (&ThisNetworkInterface->Entry);
+  mNumNetworkInterface --;
+  FreePool (ThisNetworkInterface);
+  return Status;
+}
+
+/**
+  Tests to see if the required protocols are provided on the given
+  controller handle.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @retval EFI_SUCCESS              One of required protocol is found.
+  @retval EFI_UNSUPPORTED          None of required protocol is found.
+**/
+EFI_STATUS
+TestForRequiredProtocols (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE ControllerHandle
+  )
+{
+  UINT32 Id;
+  UINTN Index;
+  EFI_STATUS Status;
+
+  for (Index = 0; Index < (sizeof (gRequiredProtocol) / sizeof (REDFISH_DISCOVER_REQUIRED_PROTOCOL)); Index ++) {
+    Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+    if (!EFI_ERROR (Status)) {
+      Status = gBS->OpenProtocol (
+                      ControllerHandle,
+                      gRequiredProtocol [Index].DiscoveredProtocolGuid,
+                      (VOID **) &Id,
+                      This->DriverBindingHandle,
+                      ControllerHandle,
+                      EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                      );
+      if (EFI_ERROR (Status)) {
+        DEBUG((DEBUG_ERROR, "%a: %s is found on this controller handle.\n", __FUNCTION__, gRequiredProtocol [Index].ProtocolName));
+        return EFI_SUCCESS;
+      }
+    }
+  }
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Build up network interface and create corresponding service through the given
+  controller handle.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @retval EFI_SUCCESS              One of required protocol is found.
+  @retval EFI_UNSUPPORTED          None of required protocol is found.
+  @retval EFI_UNSUPPORTED          Failed to build up network interface.
+**/
+EFI_STATUS
+BuildupNetworkInterface (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE ControllerHandle
+  )
+{
+  UINT32 Id;
+  UINT32 Index;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NetworkInterface;
+  BOOLEAN IsNew;
+  EFI_STATUS Status;
+  VOID *TempInterface;
+  VOID **Interface;
+  UINT32 *ProtocolDiscoverIdPtr;
+  EFI_HANDLE OpenDriverAgentHandle;
+  EFI_HANDLE OpenDriverControllerHandle;
+  EFI_HANDLE *HandleOfProtocolInterfacePtr;
+  EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *RestExInstance;
+  EFI_TPL OldTpl;
+  BOOLEAN NewNetworkInterfaceInstalled;
+
+  NewNetworkInterfaceInstalled = FALSE;
+  Index = 0;
+  do {
+    Status = gBS->OpenProtocol ( // Already in list?
+                    ControllerHandle,
+                    gRequiredProtocol [Index].DiscoveredProtocolGuid,
+                    (VOID **) &Id,
+                    This->DriverBindingHandle,
+                    ControllerHandle,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if (!EFI_ERROR (Status)) {
+      Index ++;
+      if (Index == (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
+        break;
+      }
+      continue;
+    }
+
+    Status = gBS->OpenProtocol (
+                    ControllerHandle,
+                    gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid,
+                    &TempInterface,
+                    This->DriverBindingHandle,
+                    ControllerHandle,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if (EFI_ERROR (Status)) {
+      Index ++;
+      if (Index == (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
+        break;
+      }
+      continue;
+    }
+    if (gRequiredProtocol [Index].ProtocolType != ProtocolTypeRestEx) {
+      OldTpl = gBS->RaiseTPL (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
+      Status = CreateRedfishDiscoverNetworkInterface(ControllerHandle, gRequiredProtocol [Index].ProtocolType, &IsNew, &NetworkInterface);
+      if (EFI_ERROR (Status)) {
+        gBS->RestoreTPL (OldTpl);
+        return Status;
+      }
+      NetworkInterface->NetworkProtocolType = gRequiredProtocol [Index].ProtocolType;
+      NetworkInterface->OpenDriverAgentHandle = This->DriverBindingHandle;
+      NetworkInterface->OpenDriverControllerHandle = ControllerHandle;
+      NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolGuid = \
+        *gRequiredProtocol [Index].RequiredProtocolGuid;
+      NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolServiceGuid = \
+        *gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid;
+      ProtocolDiscoverIdPtr = &NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolDiscoverId;
+      OpenDriverAgentHandle = NetworkInterface->OpenDriverAgentHandle;
+      OpenDriverControllerHandle = NetworkInterface->OpenDriverControllerHandle;
+      HandleOfProtocolInterfacePtr = &NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle;
+      Interface = &NetworkInterface->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
+      NewNetworkInterfaceInstalled = TRUE;
+      if (IsNew) {
+        InsertTailList (&mEfiRedfishDiscoverNetworkInterface, &NetworkInterface->Entry);
+        mNumNetworkInterface ++;
+      }
+      gBS->RestoreTPL (OldTpl);
+    } else {
+      // Record REST_EX instance. REST_EX is created when clinet asks for Redfish service discovery.
+      // Redfish Service Discover protocol will match REST EX to the corresponding EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
+      // when discovery.
+
+      RestExInstance = (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL));
+      if (RestExInstance == NULL) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+      RestExInstance->OpenDriverAgentHandle = This->DriverBindingHandle;
+      RestExInstance->OpenDriverControllerHandle = ControllerHandle;
+      RestExInstance->RestExControllerHandle = ControllerHandle;
+      InitializeListHead (&RestExInstance->Entry);
+      InsertTailList (&mEfiRedfishDiscoverRestExInstance, &RestExInstance->Entry);
+      mNumRestExInstance ++;
+      ProtocolDiscoverIdPtr = &RestExInstance->RestExId;
+      OpenDriverAgentHandle = RestExInstance->OpenDriverAgentHandle;
+      OpenDriverControllerHandle = RestExInstance->OpenDriverControllerHandle;
+      HandleOfProtocolInterfacePtr = &RestExInstance->RestExChildHandle;
+      Interface = (VOID **)&RestExInstance->RestExProtocolInterface;
+    }
+    Status = gBS->InstallProtocolInterface (
+                    &ControllerHandle,
+                    gRequiredProtocol [Index].DiscoveredProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    ProtocolDiscoverIdPtr
+                    );
+    if (EFI_ERROR (Status)) {
+      Index ++;
+      if (Index == (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
+        break;
+      }
+      continue;
+    }
+    //
+    // Create service binding child and open it BY_DRIVER.
+    //
+    Status = NetLibCreateServiceChild (
+              ControllerHandle,
+              This->ImageHandle,
+              gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid,
+              HandleOfProtocolInterfacePtr
+              );
+    if (!EFI_ERROR (Status)) {
+      Status = gBS->OpenProtocol (
+                    *HandleOfProtocolInterfacePtr,
+                    gRequiredProtocol [Index].RequiredProtocolGuid,
+                    Interface,
+                    OpenDriverAgentHandle,
+                    OpenDriverControllerHandle,
+                    EFI_OPEN_PROTOCOL_BY_DRIVER
+                    );
+      if (!EFI_ERROR (Status)) {
+        if (EfiRedfishDiscoverProtocolHandle == NULL &&
+            (gRequiredProtocol [Index].ProtocolType == ProtocolTypeRestEx) &&
+            !IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)
+            ) {
+          // Install the fisrt Redfish Discover Protocol when EFI REST EX protcol is discovered.
+          // This ensures EFI REST EX is ready while EFI_REDFISH_DISCOVER_PROTOCOL consumer acquires
+          // Redfish serivce over network interface.
+
+          Status = gBS->InstallProtocolInterface (
+                          &EfiRedfishDiscoverProtocolHandle,
+                          &gEfiRedfishDiscoverProtocolGuid,
+                          EFI_NATIVE_INTERFACE,
+                          (VOID *)&mRedfishDiscover
+                          );
+        } else if (EfiRedfishDiscoverProtocolHandle != NULL && NewNetworkInterfaceInstalled) {
+           Status = gBS->ReinstallProtocolInterface (
+                            EfiRedfishDiscoverProtocolHandle,
+                            &gEfiRedfishDiscoverProtocolGuid,
+                            (VOID *)&mRedfishDiscover,
+                            (VOID *)&mRedfishDiscover
+                            );
+           NewNetworkInterfaceInstalled = FALSE;
+        }
+      }
+      return Status;
+    } else {
+      Index ++;
+      if (Index == (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
+        break;
+      }
+      continue;
+    }
+  } while (Index < (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL)));
+  return EFI_UNSUPPORTED;
+}
+/**
+  Close the protocol opened for Redfish discovery. This function also destories
+  the network services.
+
+  @param[in]  ThisBindingProtocol     A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle        The handle of the controller to test. This handle
+                                      must support a protocol interface that supplies
+                                      an I/O abstraction to the driver.
+  @param[in]  ThisRequiredProtocol    Pointer to the instance of REDFISH_DISCOVER_REQUIRED_PROTOCOL.
+  @param[in]  DriverAgentHandle      Driver agent handle which used to open protocol earlier.
+  @param[in]  DriverControllerHandle Driver controller handle which used to open protocol earlier.
+
+  @retval EFI_SUCCESS                Prorocol is closed successfully.
+  @retval Others                     Prorocol is closed unsuccessfully.
+
+**/
+EFI_STATUS
+CloseProtocolService (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *ThisBindingProtocol,
+  IN EFI_HANDLE  ControllerHandle,
+  IN REDFISH_DISCOVER_REQUIRED_PROTOCOL *ThisRequiredProtocol,
+  IN EFI_HANDLE DriverAgentHandle,
+  IN EFI_HANDLE DriverControllerHandle
+)
+{
+  EFI_STATUS Status;
+
+  Status = gBS->CloseProtocol (
+                   ControllerHandle,
+                   ThisRequiredProtocol->RequiredProtocolGuid,
+                   DriverAgentHandle,
+                   DriverControllerHandle
+                   );
+  if (!EFI_ERROR (Status)) {
+    NetLibDestroyServiceChild(
+      ControllerHandle,
+      ThisBindingProtocol->ImageHandle,
+      ThisRequiredProtocol->RequiredServiceBindingProtocolGuid,
+      ControllerHandle
+      );
+  }
+  return Status;
+}
+/**
+  Stop the services on network interface.
+
+  @param[in]  ThisBindingProtocol  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @retval EFI_SUCCESS              One of required protocol is found.
+  @retval Others                   Faile to stop the services on network interface.
+**/
+EFI_STATUS
+StopServiceOnNetworkInterface (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *ThisBindingProtocol,
+  IN EFI_HANDLE ControllerHandle
+  )
+{
+  UINT32 Index;
+  EFI_STATUS Status;
+  VOID *Interface;
+  EFI_TPL OldTpl;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
+  EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *RestExInstance;
+
+  for (Index = 0; Index < (sizeof (gRequiredProtocol) / sizeof (REDFISH_DISCOVER_REQUIRED_PROTOCOL)); Index ++) {
+    Status = gBS->HandleProtocol (
+                  ControllerHandle,
+                  gRequiredProtocol [Index].RequiredProtocolGuid,
+                  (VOID **)&Interface
+                  );
+    if (!EFI_ERROR (Status)) {
+      if (gRequiredProtocol [Index].ProtocolType != ProtocolTypeRestEx) {
+        if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
+          return EFI_NOT_FOUND;
+        }
+        OldTpl = gBS->RaiseTPL (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
+        ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+        while (TRUE) {
+          if (ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle == ControllerHandle) {
+
+            Status = CloseProtocolService ( // Close protocol and destroy service.
+                       ThisBindingProtocol,
+                       ControllerHandle,
+                       &gRequiredProtocol [Index],
+                       ThisNetworkInterface->OpenDriverAgentHandle,
+                       ThisNetworkInterface->OpenDriverControllerHandle
+                       );
+            if (!EFI_ERROR (Status)) {
+              Status = DestroyRedfishNetwrokInterface (ThisNetworkInterface);
+            }
+            gBS->RestoreTPL (OldTpl);
+            // Reinstall Redfish Discover protocol to notify network
+            // interface change.
+
+            Status = gBS->ReinstallProtocolInterface (
+                            EfiRedfishDiscoverProtocolHandle,
+                            &gEfiRedfishDiscoverProtocolGuid,
+                            (VOID *)&mRedfishDiscover,
+                            (VOID *)&mRedfishDiscover
+                            );
+            if (EFI_ERROR (Status)) {
+              DEBUG((DEBUG_ERROR, "%a: Reinstall gEfiRedfishDiscoverProtocolGuid fail.", __FUNCTION__));
+            }
+            return Status;
+          }
+          if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
+            break;
+          }
+          ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
+        };
+        gBS->RestoreTPL (OldTpl);
+      } else {
+        if (IsListEmpty (&mEfiRedfishDiscoverRestExInstance)) {
+          return EFI_NOT_FOUND;
+        }
+        OldTpl = gBS->RaiseTPL (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
+        RestExInstance = (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverRestExInstance);
+        while (TRUE) {
+          if (RestExInstance->RestExChildHandle == ControllerHandle) {
+            Status = CloseProtocolService ( // Close REST_EX protocol.
+                       ThisBindingProtocol,
+                       ControllerHandle,
+                       &gRequiredProtocol [Index],
+                       RestExInstance->OpenDriverAgentHandle,
+                       RestExInstance->OpenDriverControllerHandle
+                       );
+            RemoveEntryList (&RestExInstance->Entry);
+            FreePool ((VOID *)RestExInstance);
+            mNumRestExInstance --;
+            gBS->RestoreTPL (OldTpl);
+            return Status;
+          }
+          if (IsNodeAtEnd (&mEfiRedfishDiscoverRestExInstance, &RestExInstance->Entry)) {
+            break;
+          }
+          RestExInstance = (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverRestExInstance, &RestExInstance->Entry);
+        };
+        gBS->RestoreTPL (OldTpl);
+      }
+    }
+  }
+  return EFI_NOT_FOUND;
+}
+/**
+  Tests to see if this driver supports a given controller. If a child device is provided,
+  it further tests to see if this driver supports creating a handle for the specified child device.
+
+  This function checks to see if the driver specified by This supports the device specified by
+  ControllerHandle. Drivers will typically use the device path attached to
+  ControllerHandle and/or the services from the bus I/O abstraction attached to
+  ControllerHandle to determine if the driver supports ControllerHandle. This function
+  may be called many times during platform initialization. In order to reduce boot times, the tests
+  performed by this function must be very small, and take as little time as possible to execute. This
+  function must not change the state of any hardware devices, and this function must be aware that the
+  device specified by ControllerHandle may already be managed by the same driver or a
+  different driver. This function must match its calls to AllocatePages() with FreePages(),
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required
+  to guarantee the state of ControllerHandle is not modified by this function.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
+                                   parameter is ignored by device drivers, and is optional for bus
+                                   drivers. For bus drivers, if this parameter is not NULL, then
+                                   the bus driver must determine if the bus controller specified
+                                   by ControllerHandle and the child controller specified
+                                   by RemainingDevicePath are both supported by this
+                                   bus driver.
+
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and
+                                   RemainingDevicePath is supported by the driver specified by This.
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed by the driver
+                                   specified by This.
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed by a different
+                                   driver or an application that requires exclusive access.
+                                   Currently not implemented.
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
+                                   RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  )
+{
+  return TestForRequiredProtocols (This, ControllerHandle);
+}
+
+/**
+  Starts a device controller or a bus controller.
+
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().
+  As a result, much of the error checking on the parameters to Start() has been moved into this
+  common boot service. It is legal to call Start() from other locations,
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE.
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+     EFI_DEVICE_PATH_PROTOCOL.
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle
+                                   must support a protocol interface that supplies
+                                   an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
+                                   parameter is ignored by device drivers, and is optional for bus
+                                   drivers. For a bus driver, if this parameter is NULL, then handles
+                                   for all the children of Controller are created by this driver.
+                                   If this parameter is not NULL and the first Device Path Node is
+                                   not the End of Device Path Node, then only the handle for the
+                                   child device specified by the first Device Path Node of
+                                   RemainingDevicePath is created by this driver.
+                                   If the first Device Path Node of RemainingDevicePath is
+                                   the End of Device Path Node, no child handle is created by this
+                                   driver.
+
+  @retval EFI_SUCCESS              The device was started.
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
+  @retval Others                   The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  )
+{
+  return BuildupNetworkInterface (This, ControllerHandle);
+}
+
+/**
+  Stops a device controller or a bus controller.
+
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+  As a result, much of the error checking on the parameters to Stop() has been moved
+  into this common boot service. It is legal to call Stop() from other locations,
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+     same driver's Start() function.
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+     Start() function, and the Start() function must have called OpenProtocol() on
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
+                                support a bus specific I/O protocol for the driver
+                                to use to stop the device.
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
+                                if NumberOfChildren is 0.
+
+  @retval EFI_SUCCESS           The device was stopped.
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverDriverBindingStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN UINTN                        NumberOfChildren,
+  IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
+  )
+{
+  return StopServiceOnNetworkInterface (This, ControllerHandle);
+}
+
+EFI_DRIVER_BINDING_PROTOCOL gRedfishDiscoverDriverBinding = {
+  RedfishDiscoverDriverBindingSupported,
+  RedfishDiscoverDriverBindingStart,
+  RedfishDiscoverDriverBindingStop,
+  REDFISH_DISCOVER_VERSION,
+  NULL,
+  NULL
+};
+
+/**
+  This is the declaration of an EFI image entry point.
+
+  @param  ImageHandle           The firmware allocated handle for the UEFI image.
+  @param  SystemTable           A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval Others                An unexpected error occurred.
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS Status;
+
+  Status = EFI_SUCCESS;
+  InitializeListHead (&mRedfishDiscoverList);
+  InitializeListHead (&mRedfishInstanceList);
+  InitializeListHead (&mEfiRedfishDiscoverNetworkInterface);
+  InitializeListHead (&mEfiRedfishDiscoverRestExInstance);
+  //
+  // Install binding protoocl to obtain UDP and REST EX protocol.
+  //
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle,
+             SystemTable,
+             &gRedfishDiscoverDriverBinding,
+             ImageHandle,
+             &gRedfishDiscoverComponentName,
+             &gRedfishDiscoverComponentName2
+             );
+  return Status;
+}
+
+/**
+  This is the unload handle for Redfish discover module.
+
+  Disconnect the driver specified by ImageHandle from all the devices in the handle database.
+  Uninstall all the protocols installed in the driver entry point.
+
+  @param[in] ImageHandle           The drivers' driver image.
+
+  @retval    EFI_SUCCESS           The image is unloaded.
+  @retval    Others                Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishDiscoverUnload (
+  IN EFI_HANDLE ImageHandle
+  )
+{
+  EFI_STATUS Status;
+  EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
+
+  Status = EFI_SUCCESS;
+  // Destroy all network interfaces found by EFI Redfish Discover driver and
+  // stop services created for Redfish Discover.
+
+  while (!IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
+    ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
+    StopServiceOnNetworkInterface (&gRedfishDiscoverDriverBinding, ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle);
+  };
+  // Disconnect EFI Redfish discover driver controller to notify the
+  // clinet which uses .EFI Redfish discover protocol.
+
+  if (EfiRedfishDiscoverProtocolHandle != NULL) {
+    //
+    // Notify user EFI_REDFISH_DISCOVER_PROTOCOL is unloaded.
+    //
+    gBS->DisconnectController (EfiRedfishDiscoverProtocolHandle, NULL, NULL);
+    Status = gBS->UninstallProtocolInterface(
+                    EfiRedfishDiscoverProtocolHandle,
+                    &gEfiRedfishDiscoverProtocolGuid,
+                    (VOID *)&mRedfishDiscover
+                    );
+  }
+  return Status;
+}
diff --git a/RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c b/RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
new file mode 100644
index 0000000000..f3ad36ec3a
--- /dev/null
+++ b/RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c
@@ -0,0 +1,118 @@
+/** @file
+  RedfishSmbiosHostInterface.c
+
+  Discover Redfish SMBIOS Host Interface.
+
+  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishDiscoverInternal.h"
+
+SMBIOS_TABLE_TYPE42  *mType42Record;
+
+/**
+  The function gets information reported in Redfish Host Interface.
+
+  It simply frees the packet.
+
+  @param[in]  Smbios           SMBIOS protocol.
+  @param[out] DeviceDescriptor Pointer to REDFISH_INTERFACE_DATA.
+  @param[out] ProtocolData     Pointer to REDFISH_OVER_IP_PROTOCOL_DATA.
+
+  @retval EFI_SUCCESS    Get host interface succesfully.
+  @retval Otherwise      Fail to tet host interface.
+
+**/
+EFI_STATUS
+RedfishGetHostInterfaceProtocolData (
+  IN EFI_SMBIOS_PROTOCOL              *Smbios,
+  OUT REDFISH_INTERFACE_DATA          **DeviceDescriptor,
+  OUT REDFISH_OVER_IP_PROTOCOL_DATA   **ProtocolData
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_SMBIOS_HANDLE                 SmbiosHandle;
+  EFI_SMBIOS_TABLE_HEADER           *Record;
+  UINT16                            Offset;
+  UINT8                             *RecordTmp;
+  UINT8                             ProtocolLength;
+  UINT8                             SpecificDataLen;
+
+  if ((Smbios == NULL) || (ProtocolData == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
+  Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
+  while (!EFI_ERROR (Status) && SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED) {
+    if (Record->Type == SMBIOS_TYPE_MANAGEMENT_CONTROLLER_HOST_INTERFACE) {
+      //
+      // Check Interface Type, should be Network Host Interface = 40h
+      //
+      mType42Record = (SMBIOS_TABLE_TYPE42 *) Record;
+      if (mType42Record->InterfaceType == MCHostInterfaceTypeNetworkHostInterface) {
+        ASSERT (Record->Length >= 9);
+        Offset = 5;
+        RecordTmp = (UINT8 *) Record + Offset;
+        //
+        // Get interface specific data length.
+        //
+        SpecificDataLen = *RecordTmp;
+        Offset += 1;
+        RecordTmp = (UINT8 *) Record + Offset;
+
+        //
+        // Check Device Type, only PCI/PCIe Network Interface v2 is supported now.
+        //
+        if (*RecordTmp == REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2) {
+          ASSERT (SpecificDataLen == sizeof (PCI_OR_PCIE_INTERFACE_DEVICE_DESCRIPTOR_V2) + 1);
+          *DeviceDescriptor = (REDFISH_INTERFACE_DATA *)RecordTmp;
+          Offset = Offset + SpecificDataLen;
+          RecordTmp = (UINT8 *) Record + Offset;
+          //
+          // Check Protocol count. if > 1, only use the first protocol.
+          //
+          ASSERT (*RecordTmp == 1);
+          Offset += 1;
+          RecordTmp = (UINT8 *) Record + Offset;
+          //
+          // Check protocol identifier.
+          //
+          if (*RecordTmp == MCHostInterfaceProtocolTypeRedfishOverIP) {
+            Offset += 1;
+            RecordTmp = (UINT8 *) Record + Offset;
+            ProtocolLength = *RecordTmp;
+
+            Offset += 1;
+            RecordTmp = (UINT8 *) Record + Offset;
+
+            //
+            // This SMBIOS record is invalid, if the length of protocol specific data for
+            // Redfish Over IP protocol is wrong.
+            //
+            if ((*(RecordTmp + 90) + sizeof (REDFISH_OVER_IP_PROTOCOL_DATA) - 1) != ProtocolLength) {
+              return EFI_SECURITY_VIOLATION;
+            }
+
+            Offset += ProtocolLength;
+            //
+            // This SMBIOS record is invalid, if the length is smaller than the offset.
+            //
+            if (Offset > mType42Record->Hdr.Length) {
+              return EFI_SECURITY_VIOLATION;
+            }
+            *ProtocolData = (REDFISH_OVER_IP_PROTOCOL_DATA *)RecordTmp;
+            return EFI_SUCCESS;
+          }
+        }
+      }
+    }
+    Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
+  }
+
+  *ProtocolData = NULL;
+  return EFI_NOT_FOUND;
+}
-- 
2.17.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#73933): https://edk2.groups.io/g/devel/message/73933
Mute This Topic: https://groups.io/mt/81621784/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-