<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255);">
<span style="color: rgb(0, 0, 0); font-family: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif; font-size: 14.6667px; background-color: rgb(255, 255, 255); display: inline !important;">Reviewed-by:
 Nickle Wang <nickle.wang@hpe.com></span><br>
</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255);">
<span style="color: rgb(0, 0, 0); font-family: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif; font-size: 14.6667px; background-color: rgb(255, 255, 255); display: inline !important;"><br>
</span></div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255);">
<span style="color: rgb(0, 0, 0); font-family: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif; font-size: 14.6667px; background-color: rgb(255, 255, 255); display: inline !important;">Thanks,</span></div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255);">
<span style="color: rgb(0, 0, 0); font-family: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif; font-size: 14.6667px; background-color: rgb(255, 255, 255); display: inline !important;">Nickle</span></div>
<div id="appendonsend"></div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> Chang, Abner (HPS SW/FW Technologist) <abner.chang@hpe.com><br>
<b>Sent:</b> Monday, October 25, 2021 15:41<br>
<b>To:</b> devel@edk2.groups.io <devel@edk2.groups.io><br>
<b>Cc:</b> Wang, Nickle (HPS SW) <nickle.wang@hpe.com>; Liming Gao <gaoliming@byosoft.com.cn><br>
<b>Subject:</b> [PATCH 1/2] staging/RedfishClientPkg: Add EDKII ETag driver</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt;">
<div class="PlainText">Implement EDKII ETag protocol to manipulate ETag of<br>
HTTP content.<br>
<br>
Signed-off-by: Nickle Wang <nickle.wang@hpe.com><br>
Cc: Abner Chang <abner.chang@hpe.com><br>
Cc: Liming Gao <gaoliming@byosoft.com.cn><br>
---<br>
 .../RedfishETagDxe/RedfishETagDxe.inf         |  45 +<br>
 .../Protocol/EdkIIRedfishETagProtocol.h       |  76 ++<br>
 .../RedfishETagDxe/RedfishETagDxe.h           |  70 ++<br>
 .../RedfishETagDxe/RedfishETagDxe.c           | 774 ++++++++++++++++++<br>
 4 files changed, 965 insertions(+)<br>
 create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf<br>
 create mode 100644 RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h<br>
 create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h<br>
 create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c<br>
<br>
diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf<br>
new file mode 100644<br>
index 00000000000..4315b1eaa5f<br>
--- /dev/null<br>
+++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf<br>
@@ -0,0 +1,45 @@<br>
+## @file<br>
+#<br>
+#  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR><br>
+#<br>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+#<br>
+##<br>
+<br>
+[Defines]<br>
+  INF_VERSION               = 0x0001000b<br>
+  BASE_NAME                 = RedfishETagDxe<br>
+  FILE_GUID                 = F7BB0BB2-9796-485F-9F00-C0EB47E9F92B<br>
+  MODULE_TYPE               = DXE_DRIVER<br>
+  VERSION_STRING            = 1.0<br>
+  ENTRY_POINT               = RedfishETagDriverEntryPoint<br>
+  UNLOAD_IMAGE              = RedfishETagDriverUnload<br>
+<br>
+[Packages]<br>
+  MdePkg/MdePkg.dec<br>
+  MdeModulePkg/MdeModulePkg.dec<br>
+  RedfishPkg/RedfishPkg.dec<br>
+  RedfishClientPkg/RedfishClientPkg.dec<br>
+<br>
+[Sources]<br>
+  RedfishETagDxe.h<br>
+  RedfishETagDxe.c<br>
+<br>
+[LibraryClasses]<br>
+  BaseLib<br>
+  BaseMemoryLib<br>
+  DebugLib<br>
+  MemoryAllocationLib<br>
+  UefiLib<br>
+  UefiBootServicesTableLib<br>
+  UefiRuntimeServicesTableLib<br>
+  UefiDriverEntryPoint<br>
+<br>
+[Protocols]<br>
+  gEdkIIRedfishETagProtocolGuid           ## PRODUCED ##<br>
+<br>
+[Guids]<br>
+  gEfiEventExitBootServicesGuid           ## CONSUMES ## Event<br>
+<br>
+[Depex]<br>
+  TRUE<br>
diff --git a/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h b/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h<br>
new file mode 100644<br>
index 00000000000..3cbced44eb7<br>
--- /dev/null<br>
+++ b/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h<br>
@@ -0,0 +1,76 @@<br>
+/** @file<br>
+  This file defines the EDKII_REDFISH_FEATURE_PROTOCOL interface.<br>
+<br>
+  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR><br>
+<br>
+  SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+<br>
+**/<br>
+<br>
+#ifndef EDKII_REDFISH_ETAG_PROTOCOL_H_<br>
+#define EDKII_REDFISH_ETAG_PROTOCOL_H_<br>
+<br>
+typedef struct _EDKII_REDFISH_ETAG_PROTOCOL EDKII_REDFISH_ETAG_PROTOCOL;<br>
+<br>
+/**<br>
+  Get ETag string by given URI<br>
+<br>
+  @param[in]   This                    Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance.<br>
+  @param[in]   Uri                     Target URI to search.<br>
+  @param[out]  ETag                    The ETag string to corresponding URI.<br>
+<br>
+  @retval EFI_SUCCESS                  The ETag is found successfully.<br>
+  @retval EFI_INVALID_PARAMETER        Invalid parameter is given.<br>
+<br>
+**/<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_GET) (<br>
+  IN  EDKII_REDFISH_ETAG_PROTOCOL *This,<br>
+  IN  CHAR8                       *Uri,<br>
+  OUT CHAR8                       **ETag<br>
+  );<br>
+<br>
+/**<br>
+  Keep ETag string which maps to given Uri.<br>
+<br>
+  @param[in]   This                Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance.<br>
+  @param[in]   Uri                 The target Uri which related to ETag.<br>
+  @param[in]   ETag                The ETag to add. If ETag is NULL, the record of correspoonding URI will be removed.<br>
+<br>
+  @retval EFI_SUCCESS              This handler has been stoped successfully.<br>
+  @retval Others                   Some error happened.<br>
+<br>
+**/<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_SET) (<br>
+  IN  EDKII_REDFISH_ETAG_PROTOCOL   *This,<br>
+  IN  CHAR8                         *Uri,<br>
+  IN  CHAR8                         *ETag<br>
+  );<br>
+<br>
+/**<br>
+  Refresh the ETag database and save database to variable.<br>
+<br>
+  @param[in]   This                Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance.<br>
+<br>
+  @retval EFI_SUCCESS              This handler has been stoped successfully.<br>
+  @retval Others                   Some error happened.<br>
+<br>
+**/<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_FLUSH) (<br>
+  IN  EDKII_REDFISH_ETAG_PROTOCOL    *This<br>
+  );<br>
+<br>
+struct _EDKII_REDFISH_ETAG_PROTOCOL {<br>
+  EDKII_REDFISH_ETAG_PROTOCOL_GET   Get;<br>
+  EDKII_REDFISH_ETAG_PROTOCOL_SET   Set;<br>
+  EDKII_REDFISH_ETAG_PROTOCOL_FLUSH Flush;<br>
+};<br>
+<br>
+extern EFI_GUID gEdkIIRedfishETagProtocolGuid;<br>
+<br>
+#endif<br>
diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h<br>
new file mode 100644<br>
index 00000000000..c4465743133<br>
--- /dev/null<br>
+++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h<br>
@@ -0,0 +1,70 @@<br>
+/** @file<br>
+  Common header file for RedfishETagDxe driver.<br>
+<br>
+  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR><br>
+<br>
+  SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+<br>
+**/<br>
+<br>
+#ifndef REDFISH_ETAG_DXE_H_<br>
+#define REDFISH_ETAG_DXE_H_<br>
+<br>
+#include <Uefi.h><br>
+<br>
+//<br>
+// Libraries<br>
+//<br>
+#include <Library/BaseLib.h><br>
+#include <Library/BaseMemoryLib.h><br>
+#include <Library/DebugLib.h><br>
+<br>
+#include <Library/MemoryAllocationLib.h><br>
+#include <Library/UefiBootServicesTableLib.h><br>
+#include <Library/UefiDriverEntryPoint.h><br>
+#include <Library/UefiLib.h><br>
+#include <Library/UefiRuntimeServicesTableLib.h><br>
+<br>
+#include <Protocol/EdkIIRedfishETagProtocol.h><br>
+<br>
+#include <Guid/VariableFormat.h><br>
+<br>
+#define ETAG_VARIABLE_NAME    L"RedfishETag"<br>
+#define IS_EMPTY_STRING(a) ((a) == NULL || (a)[0] == '\0')<br>
+#define ETAG_DEBUG_ENABLED    0x00<br>
+<br>
+//<br>
+// Definition of REDFISH_ETAG_RECORD<br>
+//<br>
+typedef struct {<br>
+  LIST_ENTRY  List;<br>
+  CHAR8       *Uri;<br>
+  CHAR8       *ETag;<br>
+  UINTN       Size;<br>
+} REDFISH_ETAG_RECORD;<br>
+<br>
+#define REDFISH_ETAG_RECORD_FROM_LIST(a)  BASE_CR (a, REDFISH_ETAG_RECORD, List)<br>
+<br>
+//<br>
+// Definition of REDFISH_ETAG_LIST<br>
+//<br>
+typedef struct {<br>
+  LIST_ENTRY    Listheader;<br>
+  UINTN         TotalSize;<br>
+  UINTN         Count;<br>
+} REDFISH_ETAG_LIST;<br>
+<br>
+//<br>
+// Definition of REDFISH_ETAG_PRIVATE_DATA<br>
+//<br>
+typedef struct {<br>
+  EFI_HANDLE                  ImageHandle;<br>
+  REDFISH_ETAG_LIST           ETagList;<br>
+  EDKII_REDFISH_ETAG_PROTOCOL Protocol;<br>
+  EFI_STRING                  VariableName;<br>
+  EFI_EVENT                   Event;<br>
+} REDFISH_ETAG_PRIVATE_DATA;<br>
+<br>
+#define REDFISH_ETAG_PRIVATE_FROM_THIS(a)  BASE_CR (a, REDFISH_ETAG_PRIVATE_DATA, Protocol)<br>
+<br>
+#endif<br>
diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c<br>
new file mode 100644<br>
index 00000000000..349175340d4<br>
--- /dev/null<br>
+++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c<br>
@@ -0,0 +1,774 @@<br>
+/** @file<br>
+<br>
+  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR><br>
+<br>
+  SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+<br>
+**/<br>
+<br>
+#include "RedfishETagDxe.h"<br>
+<br>
+REDFISH_ETAG_PRIVATE_DATA  *mRedfishETagPrivate = NULL;<br>
+<br>
+/**<br>
+  Release REDFISH_ETAG_RECORD resource<br>
+<br>
+  @param[in]    Record    Pointer to REDFISH_ETAG_RECORD instance<br>
+<br>
+  @retval EFI_SUCCESS             REDFISH_ETAG_RECORD is released successfully.<br>
+  @retval EFI_INVALID_PARAMETER   Record is NULL<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+ReleaseETagRecord (<br>
+  IN REDFISH_ETAG_RECORD *Record<br>
+  )<br>
+{<br>
+  if (Record == NULL) {<br>
+    return EFI_INVALID_PARAMETER;<br>
+  }<br>
+<br>
+  if (Record->Uri != NULL) {<br>
+    FreePool (Record->Uri);<br>
+  }<br>
+<br>
+  if (Record->ETag != NULL) {<br>
+    FreePool (Record->ETag);<br>
+  }<br>
+<br>
+  FreePool (Record);<br>
+<br>
+  return EFI_SUCCESS;<br>
+}<br>
+<br>
+/**<br>
+  Create new Etag resource.<br>
+<br>
+  @param[in]    Uri   The URI string matching to this ETAG.<br>
+  @param[in]    ETag  ETAG string.<br>
+<br>
+  @retval REDFISH_ETAG_RECORD *   Pointer to newly created ETAG.<br>
+  @retval NULL                    No memory available.<br>
+<br>
+**/<br>
+REDFISH_ETAG_RECORD *<br>
+NewETagRecord (<br>
+  IN  CHAR8   *Uri,<br>
+  IN  CHAR8   *ETag<br>
+  )<br>
+{<br>
+  REDFISH_ETAG_RECORD *NewRecord;<br>
+  UINTN               Size;<br>
+<br>
+  if (IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (ETag)) {<br>
+    return NULL;<br>
+  }<br>
+<br>
+  NewRecord = AllocateZeroPool (sizeof (REDFISH_ETAG_RECORD));<br>
+  if (NewRecord == NULL) {<br>
+    return NULL;<br>
+  }<br>
+<br>
+  Size = AsciiStrSize (Uri);<br>
+  NewRecord->Uri = AllocateCopyPool (Size, Uri);<br>
+  if (NewRecord->Uri == NULL) {<br>
+    goto ON_ERROR;<br>
+  }<br>
+<br>
+  NewRecord->Size = Size;<br>
+  Size = AsciiStrSize (ETag);<br>
+  NewRecord->ETag = AllocateCopyPool (Size, ETag);<br>
+  if (NewRecord->ETag == NULL) {<br>
+    goto ON_ERROR;<br>
+  }<br>
+<br>
+  NewRecord->Size += Size;<br>
+  return NewRecord;<br>
+<br>
+ON_ERROR:<br>
+<br>
+  if (NewRecord != NULL) {<br>
+    ReleaseETagRecord (NewRecord);<br>
+  }<br>
+<br>
+  return NULL;<br>
+}<br>
+<br>
+/**<br>
+  Add new ETAG by given URI and ETAG string to specify List.<br>
+<br>
+  @param[in]    List  Target ETAG list to add.<br>
+  @param[in]    Uri   The URI string matching to this ETAG.<br>
+  @param[in]    ETag  ETAG string.<br>
+<br>
+  @retval EFI_SUCCESS   ETAG recourd is added.<br>
+  @retval Others        Fail to add ETAG.<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+AddETagRecord (<br>
+  IN  REDFISH_ETAG_LIST *List,<br>
+  IN  CHAR8             *Uri,<br>
+  IN  CHAR8             *ETag<br>
+  )<br>
+{<br>
+  REDFISH_ETAG_RECORD *NewRecord;<br>
+<br>
+  if (List == NULL || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (ETag)) {<br>
+    return EFI_INVALID_PARAMETER;<br>
+  }<br>
+<br>
+  NewRecord = NewETagRecord (Uri, ETag);<br>
+  if (NewETagRecord == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  InsertTailList (&List->Listheader, &NewRecord->List);<br>
+  ++List->Count;<br>
+  List->TotalSize += NewRecord->Size;<br>
+<br>
+  return EFI_SUCCESS;<br>
+}<br>
+<br>
+/**<br>
+  Delete an ETAG by given ETAG instance.<br>
+<br>
+  @param[in]    List    Target ETAG list to be removed.<br>
+  @param[in]    Record  Pointer to the instance to be deleted.<br>
+<br>
+  @retval EFI_SUCCESS   ETAG recourd is removed.<br>
+  @retval Others        Fail to add ETAG.<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+DeleteETagRecord (<br>
+  IN  REDFISH_ETAG_LIST   *List,<br>
+  IN  REDFISH_ETAG_RECORD *Record<br>
+  )<br>
+{<br>
+  if (List == NULL || Record == NULL) {<br>
+    return EFI_INVALID_PARAMETER;<br>
+  }<br>
+<br>
+  RemoveEntryList (&Record->List);<br>
+  --List->Count;<br>
+  List->TotalSize -= Record->Size;<br>
+<br>
+  return ReleaseETagRecord (Record);<br>
+}<br>
+<br>
+/**<br>
+  Search on given ListHeader for given URI string.<br>
+<br>
+  @param[in]    ListHeader  Target list to search.<br>
+  @param[in]    Uri         Target URI to search.<br>
+<br>
+  @retval REDFISH_ETAG_RECORD   Target ETAG is found.<br>
+  @retval NULL                  No ETAG with given URI is found.<br>
+<br>
+**/<br>
+REDFISH_ETAG_RECORD *<br>
+FindETagRecord (<br>
+  IN  LIST_ENTRY  *ListHeader,<br>
+  IN  CHAR8       *Uri<br>
+  )<br>
+{<br>
+  LIST_ENTRY          *List;<br>
+  REDFISH_ETAG_RECORD *Record;<br>
+<br>
+  if (IsListEmpty (ListHeader)) {<br>
+    return NULL;<br>
+  }<br>
+<br>
+  Record = NULL;<br>
+  List = GetFirstNode (ListHeader);<br>
+  while (!IsNull (ListHeader, List)) {<br>
+    Record = REDFISH_ETAG_RECORD_FROM_LIST (List);<br>
+<br>
+    if (AsciiStrCmp (Record->Uri, Uri) == 0) {<br>
+      return  Record;<br>
+    }<br>
+<br>
+    List = GetNextNode (ListHeader, List);<br>
+  }<br>
+<br>
+  return NULL;<br>
+}<br>
+<br>
+#if ETAG_DEBUG_ENABLED<br>
+/**<br>
+  Debug output the ETAG list.<br>
+<br>
+  @param[in]    ETagList  Target list to dump<br>
+  @param[in]    Msg       Debug message string.<br>
+<br>
+  @retval EFI_SUCCESS             Debug dump finished.<br>
+  @retval EFI_INVALID_PARAMETER   ETagList is NULL.<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+DumpETagList (<br>
+  IN  REDFISH_ETAG_LIST   *ETagList,<br>
+  IN  EFI_STRING          Msg<br>
+  )<br>
+{<br>
+  LIST_ENTRY          *List;<br>
+  REDFISH_ETAG_RECORD *Record;<br>
+<br>
+  if (ETagList == NULL) {<br>
+    return EFI_INVALID_PARAMETER;<br>
+  }<br>
+<br>
+  if (!IS_EMPTY_STRING (Msg)) {<br>
+    DEBUG ((DEBUG_ERROR, "%s\n", Msg));<br>
+  }<br>
+<br>
+  if (IsListEmpty (&ETagList->Listheader)) {<br>
+    DEBUG ((DEBUG_INFO, "ETag list is empty\n"));<br>
+    return EFI_NOT_FOUND;<br>
+  }<br>
+<br>
+  DEBUG ((DEBUG_INFO, "Count: %d Total Size: %d\n", ETagList->Count, ETagList->TotalSize));<br>
+  Record = NULL;<br>
+  List = GetFirstNode (&ETagList->Listheader);<br>
+  while (!IsNull (&ETagList->Listheader, List)) {<br>
+    Record = REDFISH_ETAG_RECORD_FROM_LIST (List);<br>
+<br>
+    DEBUG ((DEBUG_INFO, "ETag: %a Uri: %a Size: %d\n", Record->ETag, Record->Uri, Record->Size));<br>
+<br>
+    List = GetNextNode (&ETagList->Listheader, List);<br>
+  }<br>
+<br>
+  return EFI_SUCCESS;<br>
+}<br>
+<br>
+/**<br>
+  Debug output raw data buffer.<br>
+<br>
+  @param[in]    Buffer      Debug output data buffer.<br>
+  @param[in]    BufferSize  The size of Buffer in byte.<br>
+<br>
+  @retval EFI_SUCCESS             Debug dump finished.<br>
+  @retval EFI_INVALID_PARAMETER   Buffer is NULL.<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+DumpRawBuffer (<br>
+  IN  CHAR8    *Buffer,<br>
+  IN  UINTN     BufferSize<br>
+  )<br>
+{<br>
+  UINTN  Index;<br>
+<br>
+  if (Buffer == NULL) {<br>
+    return EFI_INVALID_PARAMETER;<br>
+  }<br>
+<br>
+  Index = 0;<br>
+<br>
+  DEBUG ((DEBUG_ERROR, "Buffer size: %d\n", BufferSize));<br>
+  while (Buffer[Index] != '\0') {<br>
+    DEBUG ((DEBUG_ERROR, "(%d) %c ", (Index + 1), Buffer[Index]));<br>
+<br>
+    ++Index;<br>
+  }<br>
+  DEBUG ((DEBUG_ERROR, "\n"));<br>
+<br>
+  return EFI_SUCCESS;<br>
+}<br>
+#endif<br>
+<br>
+/**<br>
+  Release all ETag from list.<br>
+<br>
+  @param[in]    ETagList    The list to be released.<br>
+<br>
+  @retval EFI_SUCCESS             All etag is released.<br>
+  @retval EFI_INVALID_PARAMETER   ETagList is NULL.<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+ReleaseETagList (<br>
+  IN  REDFISH_ETAG_LIST   *ETagList<br>
+  )<br>
+{<br>
+  LIST_ENTRY          *List;<br>
+  LIST_ENTRY          *Next;<br>
+  REDFISH_ETAG_RECORD *Record;<br>
+<br>
+  if (ETagList == NULL) {<br>
+    return EFI_INVALID_PARAMETER;<br>
+  }<br>
+<br>
+  if (IsListEmpty (&ETagList->Listheader)) {<br>
+    return EFI_SUCCESS;<br>
+  }<br>
+<br>
+  Record = NULL;<br>
+  Next = NULL;<br>
+  List = GetFirstNode (&ETagList->Listheader);<br>
+  while (!IsNull (&ETagList->Listheader, List)) {<br>
+    Record = REDFISH_ETAG_RECORD_FROM_LIST (List);<br>
+    Next = GetNextNode (&ETagList->Listheader, List);<br>
+<br>
+    DeleteETagRecord (ETagList, Record);<br>
+<br>
+    List = Next;<br>
+  }<br>
+<br>
+  return EFI_SUCCESS;<br>
+}<br>
+<br>
+/**<br>
+  Save etag in list to UEFI variable.<br>
+<br>
+  @param[in]    ETagList      The list to be saved.<br>
+  @param[in]    VariableName  The UEFI variable name.<br>
+<br>
+  @retval EFI_SUCCESS             All etag is saved.<br>
+  @retval EFI_INVALID_PARAMETER   VariableName or ETagList is NULL.<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+SaveETagList (<br>
+  IN  REDFISH_ETAG_LIST   *ETagList,<br>
+  IN  EFI_STRING          VariableName<br>
+  )<br>
+{<br>
+  LIST_ENTRY          *List;<br>
+  REDFISH_ETAG_RECORD *Record;<br>
+  CHAR8               *VarData;<br>
+  VOID                *Data;<br>
+  CHAR8               *Seeker;<br>
+  UINTN               VarSize;<br>
+  UINTN               StrSize;<br>
+  EFI_STATUS          Status;<br>
+<br>
+  if (ETagList == NULL || IS_EMPTY_STRING (VariableName)) {<br>
+    return EFI_INVALID_PARAMETER;<br>
+  }<br>
+<br>
+  if (IsListEmpty (&ETagList->Listheader)) {<br>
+    return EFI_SUCCESS;<br>
+  }<br>
+<br>
+  //<br>
+  // Caculate the total size we need to keep ETag list.<br>
+  //<br>
+  VarSize = ETagList->TotalSize + 1; // terminator character<br>
+  VarData = AllocateZeroPool (VarSize);<br>
+  if (VarData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  Seeker = VarData;<br>
+  Record = NULL;<br>
+  List = GetFirstNode (&ETagList->Listheader);<br>
+  while (!IsNull (&ETagList->Listheader, List)) {<br>
+    Record = REDFISH_ETAG_RECORD_FROM_LIST (List);<br>
+<br>
+    StrSize = AsciiStrSize (Record->Uri);<br>
+    CopyMem (Seeker, Record->Uri, StrSize);<br>
+<br>
+    Seeker += (StrSize - 1);<br>
+    *Seeker = '|';<br>
+    ++Seeker;<br>
+<br>
+    StrSize = AsciiStrSize (Record->ETag);<br>
+    CopyMem (Seeker, Record->ETag, StrSize);<br>
+<br>
+    Seeker += (StrSize - 1);<br>
+    *Seeker = '\n';<br>
+<br>
+    ++Seeker;<br>
+<br>
+    List = GetNextNode (&ETagList->Listheader, List);;<br>
+  }<br>
+<br>
+  *Seeker = '\0';<br>
+<br>
+#if ETAG_DEBUG_ENABLED<br>
+  DumpRawBuffer (VarData, VarSize);<br>
+#endif<br>
+<br>
+  ASSERT (((UINTN)Seeker - (UINTN)VarData + 1) == VarSize);<br>
+<br>
+  //<br>
+  // Check if variable exists already. If yes, remove it first.<br>
+  //<br>
+  Status = GetVariable2 (<br>
+             VariableName,<br>
+             &gEfiCallerIdGuid,<br>
+             (VOID *)&Data,<br>
+             NULL<br>
+             );<br>
+  if (!EFI_ERROR (Status)) {<br>
+    FreePool (Data);<br>
+    gRT->SetVariable (VariableName, &gEfiCallerIdGuid, VARIABLE_ATTRIBUTE_NV_BS, 0, NULL);<br>
+  }<br>
+<br>
+<br>
+  return gRT->SetVariable (VariableName, &gEfiCallerIdGuid, VARIABLE_ATTRIBUTE_NV_BS, VarSize, (VOID *)VarData);<br>
+}<br>
+<br>
+/**<br>
+  Read etag from UEFI variable if it exists.<br>
+<br>
+  @param[in]    ETagList      The list to be loaded.<br>
+  @param[in]    VariableName  The UEFI variable name.<br>
+<br>
+  @retval EFI_SUCCESS             All etag is read successfully.<br>
+  @retval EFI_INVALID_PARAMETER   VariableName or ETagList is NULL.<br>
+  @retval EFI_NOT_FOUND           No etag is found on UEFI variable.<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+InitialETagList (<br>
+  IN  REDFISH_ETAG_LIST   *ETagList,<br>
+  IN  EFI_STRING          VariableName<br>
+  )<br>
+{<br>
+  CHAR8     *VarData;<br>
+  CHAR8     *UriPointer;<br>
+  CHAR8     *ETagPointer;<br>
+  CHAR8     *Seeker;<br>
+  UINTN      VariableSize;<br>
+  EFI_STATUS Status;<br>
+<br>
+  if (ETagList == NULL || IS_EMPTY_STRING (VariableName)) {<br>
+    return EFI_INVALID_PARAMETER;<br>
+  }<br>
+<br>
+  //<br>
+  // Check if variable exists already.<br>
+  //<br>
+  Status = GetVariable2 (<br>
+             VariableName,<br>
+             &gEfiCallerIdGuid,<br>
+             (VOID *)&VarData,<br>
+             &VariableSize<br>
+             );<br>
+  if (EFI_ERROR (Status)) {<br>
+    return EFI_NOT_FOUND;<br>
+  }<br>
+<br>
+  Seeker = VarData;<br>
+  UriPointer = VarData;<br>
+  ETagPointer = VarData;<br>
+  while (*Seeker != '\0') {<br>
+<br>
+    //<br>
+    // Find URI<br>
+    //<br>
+    Seeker = AsciiStrStr (UriPointer, "|");<br>
+    if (Seeker == NULL) {<br>
+      DEBUG ((DEBUG_ERROR, "%a, data corrupted\n", __FUNCTION__));<br>
+      Status = EFI_DEVICE_ERROR;<br>
+      goto ON_ERROR;<br>
+    }<br>
+<br>
+    *Seeker = '\0';<br>
+    ETagPointer = ++Seeker;<br>
+<br>
+    //<br>
+    // Find ETAG<br>
+    //<br>
+    Seeker = AsciiStrStr (ETagPointer, "\n");<br>
+    if (Seeker == NULL) {<br>
+      DEBUG ((DEBUG_ERROR, "%a, data corrupted\n", __FUNCTION__));<br>
+      Status = EFI_DEVICE_ERROR;<br>
+      goto ON_ERROR;<br>
+    }<br>
+<br>
+    *Seeker = '\0';<br>
+<br>
+    AddETagRecord (ETagList, UriPointer, ETagPointer);<br>
+<br>
+    UriPointer = ++Seeker;<br>
+  }<br>
+<br>
+#if ETAG_DEBUG_ENABLED<br>
+  DumpETagList (ETagList, L"Initial ETag List from Variable");<br>
+#endif<br>
+<br>
+  Status = EFI_SUCCESS;<br>
+<br>
+ON_ERROR:<br>
+<br>
+  FreePool (VarData);<br>
+<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  Get ETag string by given URI<br>
+<br>
+  @param[in]   This                    Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance.<br>
+  @param[in]   Uri                     Target URI to search.<br>
+  @param[out]  ETag                    The ETag string to corresponding URI.<br>
+<br>
+  @retval EFI_SUCCESS                  The ETag is found successfully.<br>
+  @retval EFI_INVALID_PARAMETER        Invalid parameter is given.<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+RedfishETagGet (<br>
+  IN  EDKII_REDFISH_ETAG_PROTOCOL *This,<br>
+  IN  CHAR8                     *Uri,<br>
+  OUT CHAR8                     **ETag<br>
+  )<br>
+{<br>
+  REDFISH_ETAG_RECORD       *Target;<br>
+  REDFISH_ETAG_PRIVATE_DATA *Private;<br>
+<br>
+  if (This == NULL || IS_EMPTY_STRING (Uri) || ETag == NULL) {<br>
+    return EFI_INVALID_PARAMETER;<br>
+  }<br>
+<br>
+  Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This);<br>
+<br>
+  *ETag = NULL;<br>
+<br>
+  Target = FindETagRecord (&Private->ETagList.Listheader, Uri);<br>
+  if (Target == NULL) {<br>
+    return EFI_NOT_FOUND;<br>
+  }<br>
+<br>
+  *ETag = AllocateCopyPool (AsciiStrSize (Target->ETag), Target->ETag);<br>
+<br>
+  return EFI_SUCCESS;<br>
+}<br>
+<br>
+<br>
+/**<br>
+  Keep ETag string which maps to given Uri.<br>
+<br>
+  @param[in]   This                Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance.<br>
+  @param[in]   Uri                 The target Uri which related to ETag.<br>
+  @param[in]   ETag                The ETag to add. If ETag is NULL, the record of correspoonding URI will be removed.<br>
+<br>
+  @retval EFI_SUCCESS              This handler has been stoped successfully.<br>
+  @retval Others                   Some error happened.<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+RedfishETagSet (<br>
+  IN  EDKII_REDFISH_ETAG_PROTOCOL  *This,<br>
+  IN  CHAR8                        *Uri,<br>
+  IN  CHAR8                        *ETag  OPTIONAL<br>
+  )<br>
+{<br>
+  REDFISH_ETAG_RECORD       *Target;<br>
+  REDFISH_ETAG_PRIVATE_DATA *Private;<br>
+  EFI_STATUS                Status;<br>
+<br>
+  if (This == NULL || IS_EMPTY_STRING (Uri)) {<br>
+    return EFI_INVALID_PARAMETER;<br>
+  }<br>
+<br>
+  Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This);<br>
+<br>
+  Status = EFI_NOT_FOUND;<br>
+  Target = FindETagRecord (&Private->ETagList.Listheader, Uri);<br>
+  if (Target != NULL) {<br>
+    //<br>
+    // Remove old one and create new one.<br>
+    //<br>
+    Status = DeleteETagRecord (&Private->ETagList, Target);<br>
+  }<br>
+<br>
+  //<br>
+  // When ETag is NULL, it means that we want to remov this record.<br>
+  //<br>
+  if (ETag == NULL) {<br>
+    return Status;<br>
+  }<br>
+<br>
+  return AddETagRecord (&Private->ETagList, Uri, ETag);<br>
+}<br>
+<br>
+/**<br>
+  Refresh the ETag database and save database to variable.<br>
+<br>
+  @param[in]   This                Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance.<br>
+<br>
+  @retval EFI_SUCCESS              This handler has been stoped successfully.<br>
+  @retval Others                   Some error happened.<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+RedfishETagFlush (<br>
+  IN  EDKII_REDFISH_ETAG_PROTOCOL    *This<br>
+  )<br>
+{<br>
+  REDFISH_ETAG_PRIVATE_DATA *Private;<br>
+  EFI_STATUS                Status;<br>
+<br>
+  if (This == NULL) {<br>
+    return EFI_INVALID_PARAMETER;<br>
+  }<br>
+<br>
+  Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This);<br>
+<br>
+  Status = SaveETagList (&Private->ETagList, Private->VariableName);<br>
+  if (EFI_ERROR (Status)) {<br>
+    DEBUG ((DEBUG_ERROR, "%a, save ETag list to variable: %s failed: %r\n", __FUNCTION__, Private->VariableName, Status));<br>
+  }<br>
+<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  Callback function executed when the ExitBootService event group is signaled.<br>
+<br>
+  @param[in]   Event    Event whose notification function is being invoked.<br>
+  @param[out]  Context  Pointer to the Context buffer<br>
+<br>
+**/<br>
+VOID<br>
+EFIAPI<br>
+RedfishETagOnExitBootService (<br>
+  IN  EFI_EVENT  Event,<br>
+  OUT VOID       *Context<br>
+  )<br>
+{<br>
+  //<br>
+  // Memory is about to be released. Keep list into variable.<br>
+  //<br>
+  RedfishETagFlush (&mRedfishETagPrivate->Protocol);<br>
+}<br>
+<br>
+/**<br>
+  Unloads an image.<br>
+<br>
+  @param[in]  ImageHandle           Handle that identifies the image to be unloaded.<br>
+<br>
+  @retval EFI_SUCCESS           The image has been unloaded.<br>
+  @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+EFIAPI<br>
+RedfishETagDriverUnload (<br>
+  IN EFI_HANDLE  ImageHandle<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+<br>
+  if (mRedfishETagPrivate != NULL) {<br>
+<br>
+    Status = gBS->UninstallProtocolInterface (<br>
+                    mRedfishETagPrivate->ImageHandle,<br>
+                    &gEdkIIRedfishETagProtocolGuid,<br>
+                    (VOID*)&mRedfishETagPrivate->Protocol<br>
+                    );<br>
+    if (EFI_ERROR (Status)) {<br>
+      DEBUG ((DEBUG_ERROR, "%a, can not uninstall gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status));<br>
+      ASSERT (FALSE);<br>
+    }<br>
+<br>
+    ReleaseETagList (&mRedfishETagPrivate->ETagList);<br>
+<br>
+    if (mRedfishETagPrivate->VariableName != NULL) {<br>
+      FreePool (mRedfishETagPrivate->VariableName);<br>
+    }<br>
+<br>
+    if (mRedfishETagPrivate->Event != NULL) {<br>
+      gBS->CloseEvent (mRedfishETagPrivate->Event);<br>
+    }<br>
+<br>
+    FreePool (mRedfishETagPrivate);<br>
+    mRedfishETagPrivate = NULL;<br>
+  }<br>
+<br>
+<br>
+  return EFI_SUCCESS;<br>
+}<br>
+<br>
+//<br>
+// EDKII_REDFISH_ETAG_PROTOCOL.<br>
+//<br>
+EDKII_REDFISH_ETAG_PROTOCOL mRedfishETagProtocol = {<br>
+  RedfishETagGet,<br>
+  RedfishETagSet,<br>
+  RedfishETagFlush<br>
+};<br>
+<br>
+/**<br>
+  This is the declaration of an EFI image entry point. This entry point is<br>
+  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including<br>
+  both device drivers and bus drivers.<br>
+<br>
+  @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.<br>
+  @param[in]  SystemTable       A pointer to the EFI System Table.<br>
+<br>
+  @retval EFI_SUCCESS           The operation completed successfully.<br>
+  @retval Others                An unexpected error occurred.<br>
+**/<br>
+EFI_STATUS<br>
+EFIAPI<br>
+RedfishETagDriverEntryPoint (<br>
+  IN EFI_HANDLE        ImageHandle,<br>
+  IN EFI_SYSTEM_TABLE  *SystemTable<br>
+  )<br>
+{<br>
+  EFI_STATUS    Status;<br>
+<br>
+  mRedfishETagPrivate = AllocateZeroPool (sizeof (REDFISH_ETAG_PRIVATE_DATA));<br>
+  if (mRedfishETagPrivate == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  InitializeListHead (&mRedfishETagPrivate->ETagList.Listheader);<br>
+  mRedfishETagPrivate->VariableName = AllocateCopyPool (StrSize (ETAG_VARIABLE_NAME), ETAG_VARIABLE_NAME);<br>
+  if (mRedfishETagPrivate->VariableName == NULL) {<br>
+    goto ON_ERROR;<br>
+  }<br>
+<br>
+  mRedfishETagPrivate->ImageHandle = ImageHandle;<br>
+  CopyMem (&mRedfishETagPrivate->Protocol, &mRedfishETagProtocol, sizeof (EDKII_REDFISH_ETAG_PROTOCOL));<br>
+<br>
+  Status = gBS->InstallProtocolInterface (<br>
+                  &ImageHandle,<br>
+                  &gEdkIIRedfishETagProtocolGuid,<br>
+                  EFI_NATIVE_INTERFACE,<br>
+                  (VOID*)&mRedfishETagPrivate->Protocol<br>
+                  );<br>
+  if (EFI_ERROR (Status)) {<br>
+    DEBUG ((DEBUG_ERROR, "%a, can not install gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status));<br>
+    ASSERT (FALSE);<br>
+    goto ON_ERROR;<br>
+  }<br>
+<br>
+  //<br>
+  // Create Exit Boot Service event.<br>
+  //<br>
+  Status = gBS->CreateEventEx (<br>
+                  EVT_NOTIFY_SIGNAL,<br>
+                  TPL_CALLBACK,<br>
+                  RedfishETagOnExitBootService,<br>
+                  NULL,<br>
+                  &gEfiEventExitBootServicesGuid,<br>
+                  &mRedfishETagPrivate->Event<br>
+                  );<br>
+  if (EFI_ERROR (Status)) {<br>
+    DEBUG ((DEBUG_ERROR, "%a: Fail to register Exit Boot Service event.", __FUNCTION__));<br>
+    goto ON_ERROR;<br>
+  }<br>
+<br>
+  //<br>
+  // Read existing record from variable.<br>
+  //<br>
+  Status = InitialETagList (&mRedfishETagPrivate->ETagList, mRedfishETagPrivate->VariableName);<br>
+  if (EFI_ERROR (Status)) {<br>
+    DEBUG ((DEBUG_INFO, "%a, Initial ETag List: %r\n", __FUNCTION__, Status));<br>
+  }<br>
+<br>
+  return EFI_SUCCESS;<br>
+<br>
+ON_ERROR:<br>
+<br>
+  RedfishETagDriverUnload (ImageHandle);<br>
+<br>
+  return Status;<br>
+}<br>
-- <br>
2.21.0.windows.1<br>
<br>
</div>
</span></font></div>
</body>
</html>


 <div width="1" style="color:white;clear:both">_._,_._,_</div> <hr>   Groups.io Links:<p>   You receive all messages sent to this group.    <p> <a target="_blank" href="https://edk2.groups.io/g/devel/message/82626">View/Reply Online (#82626)</a> |    |  <a target="_blank" href="https://groups.io/mt/86572080/1813853">Mute This Topic</a>  | <a href="https://edk2.groups.io/g/devel/post">New Topic</a><br>    <a href="https://edk2.groups.io/g/devel/editsub/1813853">Your Subscription</a> | <a href="mailto:devel+owner@edk2.groups.io">Contact Group Owner</a> |  <a href="https://edk2.groups.io/g/devel/unsub">Unsubscribe</a>  [edk2-devel-archive@redhat.com]<br> <div width="1" style="color:white;clear:both">_._,_._,_</div>