]> git.proxmox.com Git - mirror_edk2.git/commitdiff
RedfishPkg/RedfishDiscoverDxe: EFI Redfish Discover Protocol
authorAbner Chang <abner.chang@hpe.com>
Wed, 24 Mar 2021 07:35:54 +0000 (15:35 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Mon, 12 Apr 2021 07:02:23 +0000 (07:02 +0000)
BZ#:2906
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>
Reviewed-by: Nickle Wang <nickle.wang@hpe.com>
RedfishPkg/Redfish.fdf.inc
RedfishPkg/RedfishComponents.dsc.inc
RedfishPkg/RedfishDiscoverDxe/ComponentName.c [new file with mode: 0644]
RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c [new file with mode: 0644]
RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.inf [new file with mode: 0644]
RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverInternal.h [new file with mode: 0644]
RedfishPkg/RedfishDiscoverDxe/RedfishSmbiosHostInterface.c [new file with mode: 0644]

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