* [edk2-redfish-client][PATCH 2/8] RedfishClientPkg: Add EDKII ETag driver
@ 2023-05-04 14:22 Nickle Wang
2023-05-05 0:55 ` Chang, Abner
[not found] ` <175C194407D29FBE.22266@groups.io>
0 siblings, 2 replies; 3+ messages in thread
From: Nickle Wang @ 2023-05-04 14:22 UTC (permalink / raw)
To: devel; +Cc: Abner Chang, Igor Kulchytskyy
Implement EDKII ETag protocol to manipulate ETag of
HTTP content.
Signed-off-by: Nickle Wang <nicklew@nvidia.com>
Cc: Abner Chang <abner.chang@amd.com>
Cc: Igor Kulchytskyy <igork@ami.com>
---
.../RedfishETagDxe/RedfishETagDxe.inf | 45 +
.../Protocol/EdkIIRedfishETagProtocol.h | 76 ++
.../RedfishETagDxe/RedfishETagDxe.h | 70 ++
.../RedfishETagDxe/RedfishETagDxe.c | 772 ++++++++++++++++++
4 files changed, 963 insertions(+)
create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf
create mode 100644 RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h
create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h
create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c
diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf
new file mode 100644
index 00000000..e29a1045
--- /dev/null
+++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf
@@ -0,0 +1,45 @@
+## @file
+#
+# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001000b
+ BASE_NAME = RedfishETagDxe
+ FILE_GUID = F7BB0BB2-9796-485F-9F00-C0EB47E9F92B
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = RedfishETagDriverEntryPoint
+ UNLOAD_IMAGE = RedfishETagDriverUnload
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ RedfishPkg/RedfishPkg.dec
+ RedfishClientPkg/RedfishClientPkg.dec
+
+[Sources]
+ RedfishETagDxe.h
+ RedfishETagDxe.c
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEdkIIRedfishETagProtocolGuid ## PRODUCED ##
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+
+[Depex]
+ TRUE
diff --git a/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h b/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h
new file mode 100644
index 00000000..4e10965a
--- /dev/null
+++ b/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h
@@ -0,0 +1,76 @@
+/** @file
+ This file defines the EDKII_REDFISH_FEATURE_PROTOCOL interface.
+
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EDKII_REDFISH_ETAG_PROTOCOL_H_
+#define EDKII_REDFISH_ETAG_PROTOCOL_H_
+
+typedef struct _EDKII_REDFISH_ETAG_PROTOCOL EDKII_REDFISH_ETAG_PROTOCOL;
+
+/**
+ Get ETag string by given URI
+
+ @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance.
+ @param[in] Uri Target URI to search.
+ @param[out] ETag The ETag string to corresponding URI.
+
+ @retval EFI_SUCCESS The ETag is found successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter is given.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_GET)(
+ IN EDKII_REDFISH_ETAG_PROTOCOL *This,
+ IN CHAR8 *Uri,
+ OUT CHAR8 **ETag
+ );
+
+/**
+ Keep ETag string which maps to given Uri.
+
+ @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance.
+ @param[in] Uri The target Uri which related to ETag.
+ @param[in] ETag The ETag to add. If ETag is NULL, the record of correspoonding URI will be removed.
+
+ @retval EFI_SUCCESS This handler has been stoped successfully.
+ @retval Others Some error happened.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_SET)(
+ IN EDKII_REDFISH_ETAG_PROTOCOL *This,
+ IN CHAR8 *Uri,
+ IN CHAR8 *ETag
+ );
+
+/**
+ Refresh the ETag database and save database to variable.
+
+ @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance.
+
+ @retval EFI_SUCCESS This handler has been stoped successfully.
+ @retval Others Some error happened.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_FLUSH)(
+ IN EDKII_REDFISH_ETAG_PROTOCOL *This
+ );
+
+struct _EDKII_REDFISH_ETAG_PROTOCOL {
+ EDKII_REDFISH_ETAG_PROTOCOL_GET Get;
+ EDKII_REDFISH_ETAG_PROTOCOL_SET Set;
+ EDKII_REDFISH_ETAG_PROTOCOL_FLUSH Flush;
+};
+
+extern EFI_GUID gEdkIIRedfishETagProtocolGuid;
+
+#endif
diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h
new file mode 100644
index 00000000..6dffa9d7
--- /dev/null
+++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h
@@ -0,0 +1,70 @@
+/** @file
+ Common header file for RedfishETagDxe driver.
+
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef REDFISH_ETAG_DXE_H_
+#define REDFISH_ETAG_DXE_H_
+
+#include <Uefi.h>
+
+//
+// Libraries
+//
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Protocol/EdkIIRedfishETagProtocol.h>
+
+#include <Guid/VariableFormat.h>
+
+#define ETAG_VARIABLE_NAME L"RedfishETag"
+#define IS_EMPTY_STRING(a) ((a) == NULL || (a)[0] == '\0')
+#define ETAG_DEBUG_ENABLED 0x00
+
+//
+// Definition of REDFISH_ETAG_RECORD
+//
+typedef struct {
+ LIST_ENTRY List;
+ CHAR8 *Uri;
+ CHAR8 *ETag;
+ UINTN Size;
+} REDFISH_ETAG_RECORD;
+
+#define REDFISH_ETAG_RECORD_FROM_LIST(a) BASE_CR (a, REDFISH_ETAG_RECORD, List)
+
+//
+// Definition of REDFISH_ETAG_LIST
+//
+typedef struct {
+ LIST_ENTRY Listheader;
+ UINTN TotalSize;
+ UINTN Count;
+} REDFISH_ETAG_LIST;
+
+//
+// Definition of REDFISH_ETAG_PRIVATE_DATA
+//
+typedef struct {
+ EFI_HANDLE ImageHandle;
+ REDFISH_ETAG_LIST ETagList;
+ EDKII_REDFISH_ETAG_PROTOCOL Protocol;
+ EFI_STRING VariableName;
+ EFI_EVENT Event;
+} REDFISH_ETAG_PRIVATE_DATA;
+
+#define REDFISH_ETAG_PRIVATE_FROM_THIS(a) BASE_CR (a, REDFISH_ETAG_PRIVATE_DATA, Protocol)
+
+#endif
diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c
new file mode 100644
index 00000000..af920afc
--- /dev/null
+++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c
@@ -0,0 +1,772 @@
+/** @file
+
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishETagDxe.h"
+
+REDFISH_ETAG_PRIVATE_DATA *mRedfishETagPrivate = NULL;
+
+/**
+ Release REDFISH_ETAG_RECORD resource
+
+ @param[in] Record Pointer to REDFISH_ETAG_RECORD instance
+
+ @retval EFI_SUCCESS REDFISH_ETAG_RECORD is released successfully.
+ @retval EFI_INVALID_PARAMETER Record is NULL
+
+**/
+EFI_STATUS
+ReleaseETagRecord (
+ IN REDFISH_ETAG_RECORD *Record
+ )
+{
+ if (Record == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Record->Uri != NULL) {
+ FreePool (Record->Uri);
+ }
+
+ if (Record->ETag != NULL) {
+ FreePool (Record->ETag);
+ }
+
+ FreePool (Record);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create new Etag resource.
+
+ @param[in] Uri The URI string matching to this ETAG.
+ @param[in] ETag ETAG string.
+
+ @retval REDFISH_ETAG_RECORD * Pointer to newly created ETAG.
+ @retval NULL No memory available.
+
+**/
+REDFISH_ETAG_RECORD *
+NewETagRecord (
+ IN CHAR8 *Uri,
+ IN CHAR8 *ETag
+ )
+{
+ REDFISH_ETAG_RECORD *NewRecord;
+ UINTN Size;
+
+ if (IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (ETag)) {
+ return NULL;
+ }
+
+ NewRecord = AllocateZeroPool (sizeof (REDFISH_ETAG_RECORD));
+ if (NewRecord == NULL) {
+ return NULL;
+ }
+
+ Size = AsciiStrSize (Uri);
+ NewRecord->Uri = AllocateCopyPool (Size, Uri);
+ if (NewRecord->Uri == NULL) {
+ goto ON_ERROR;
+ }
+
+ NewRecord->Size = Size;
+ Size = AsciiStrSize (ETag);
+ NewRecord->ETag = AllocateCopyPool (Size, ETag);
+ if (NewRecord->ETag == NULL) {
+ goto ON_ERROR;
+ }
+
+ NewRecord->Size += Size;
+ return NewRecord;
+
+ON_ERROR:
+
+ if (NewRecord != NULL) {
+ ReleaseETagRecord (NewRecord);
+ }
+
+ return NULL;
+}
+
+/**
+ Add new ETAG by given URI and ETAG string to specify List.
+
+ @param[in] List Target ETAG list to add.
+ @param[in] Uri The URI string matching to this ETAG.
+ @param[in] ETag ETAG string.
+
+ @retval EFI_SUCCESS ETAG recourd is added.
+ @retval Others Fail to add ETAG.
+
+**/
+EFI_STATUS
+AddETagRecord (
+ IN REDFISH_ETAG_LIST *List,
+ IN CHAR8 *Uri,
+ IN CHAR8 *ETag
+ )
+{
+ REDFISH_ETAG_RECORD *NewRecord;
+
+ if ((List == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (ETag)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NewRecord = NewETagRecord (Uri, ETag);
+ if (NewETagRecord == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InsertTailList (&List->Listheader, &NewRecord->List);
+ ++List->Count;
+ List->TotalSize += NewRecord->Size;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete an ETAG by given ETAG instance.
+
+ @param[in] List Target ETAG list to be removed.
+ @param[in] Record Pointer to the instance to be deleted.
+
+ @retval EFI_SUCCESS ETAG recourd is removed.
+ @retval Others Fail to add ETAG.
+
+**/
+EFI_STATUS
+DeleteETagRecord (
+ IN REDFISH_ETAG_LIST *List,
+ IN REDFISH_ETAG_RECORD *Record
+ )
+{
+ if ((List == NULL) || (Record == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RemoveEntryList (&Record->List);
+ --List->Count;
+ List->TotalSize -= Record->Size;
+
+ return ReleaseETagRecord (Record);
+}
+
+/**
+ Search on given ListHeader for given URI string.
+
+ @param[in] ListHeader Target list to search.
+ @param[in] Uri Target URI to search.
+
+ @retval REDFISH_ETAG_RECORD Target ETAG is found.
+ @retval NULL No ETAG with given URI is found.
+
+**/
+REDFISH_ETAG_RECORD *
+FindETagRecord (
+ IN LIST_ENTRY *ListHeader,
+ IN CHAR8 *Uri
+ )
+{
+ LIST_ENTRY *List;
+ REDFISH_ETAG_RECORD *Record;
+
+ if (IsListEmpty (ListHeader)) {
+ return NULL;
+ }
+
+ Record = NULL;
+ List = GetFirstNode (ListHeader);
+ while (!IsNull (ListHeader, List)) {
+ Record = REDFISH_ETAG_RECORD_FROM_LIST (List);
+
+ if (AsciiStrCmp (Record->Uri, Uri) == 0) {
+ return Record;
+ }
+
+ List = GetNextNode (ListHeader, List);
+ }
+
+ return NULL;
+}
+
+#if ETAG_DEBUG_ENABLED
+
+/**
+ Debug output the ETAG list.
+
+ @param[in] ETagList Target list to dump
+ @param[in] Msg Debug message string.
+
+ @retval EFI_SUCCESS Debug dump finished.
+ @retval EFI_INVALID_PARAMETER ETagList is NULL.
+
+**/
+EFI_STATUS
+DumpETagList (
+ IN REDFISH_ETAG_LIST *ETagList,
+ IN EFI_STRING Msg
+ )
+{
+ LIST_ENTRY *List;
+ REDFISH_ETAG_RECORD *Record;
+
+ if (ETagList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IS_EMPTY_STRING (Msg)) {
+ DEBUG ((DEBUG_ERROR, "%s\n", Msg));
+ }
+
+ if (IsListEmpty (&ETagList->Listheader)) {
+ DEBUG ((DEBUG_INFO, "ETag list is empty\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUG ((DEBUG_INFO, "Count: %d Total Size: %d\n", ETagList->Count, ETagList->TotalSize));
+ Record = NULL;
+ List = GetFirstNode (&ETagList->Listheader);
+ while (!IsNull (&ETagList->Listheader, List)) {
+ Record = REDFISH_ETAG_RECORD_FROM_LIST (List);
+
+ DEBUG ((DEBUG_INFO, "ETag: %a Uri: %a Size: %d\n", Record->ETag, Record->Uri, Record->Size));
+
+ List = GetNextNode (&ETagList->Listheader, List);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Debug output raw data buffer.
+
+ @param[in] Buffer Debug output data buffer.
+ @param[in] BufferSize The size of Buffer in byte.
+
+ @retval EFI_SUCCESS Debug dump finished.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+
+**/
+EFI_STATUS
+DumpRawBuffer (
+ IN CHAR8 *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ UINTN Index;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Index = 0;
+
+ DEBUG ((DEBUG_ERROR, "Buffer size: %d\n", BufferSize));
+ while (Buffer[Index] != '\0') {
+ DEBUG ((DEBUG_ERROR, "(%d) %c ", (Index + 1), Buffer[Index]));
+
+ ++Index;
+ }
+
+ DEBUG ((DEBUG_ERROR, "\n"));
+
+ return EFI_SUCCESS;
+}
+
+#endif
+
+/**
+ Release all ETag from list.
+
+ @param[in] ETagList The list to be released.
+
+ @retval EFI_SUCCESS All etag is released.
+ @retval EFI_INVALID_PARAMETER ETagList is NULL.
+
+**/
+EFI_STATUS
+ReleaseETagList (
+ IN REDFISH_ETAG_LIST *ETagList
+ )
+{
+ LIST_ENTRY *List;
+ LIST_ENTRY *Next;
+ REDFISH_ETAG_RECORD *Record;
+
+ if (ETagList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsListEmpty (&ETagList->Listheader)) {
+ return EFI_SUCCESS;
+ }
+
+ Record = NULL;
+ Next = NULL;
+ List = GetFirstNode (&ETagList->Listheader);
+ while (!IsNull (&ETagList->Listheader, List)) {
+ Record = REDFISH_ETAG_RECORD_FROM_LIST (List);
+ Next = GetNextNode (&ETagList->Listheader, List);
+
+ DeleteETagRecord (ETagList, Record);
+
+ List = Next;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Save etag in list to UEFI variable.
+
+ @param[in] ETagList The list to be saved.
+ @param[in] VariableName The UEFI variable name.
+
+ @retval EFI_SUCCESS All etag is saved.
+ @retval EFI_INVALID_PARAMETER VariableName or ETagList is NULL.
+
+**/
+EFI_STATUS
+SaveETagList (
+ IN REDFISH_ETAG_LIST *ETagList,
+ IN EFI_STRING VariableName
+ )
+{
+ LIST_ENTRY *List;
+ REDFISH_ETAG_RECORD *Record;
+ CHAR8 *VarData;
+ VOID *Data;
+ CHAR8 *Seeker;
+ UINTN VarSize;
+ UINTN StrSize;
+ EFI_STATUS Status;
+
+ if ((ETagList == NULL) || IS_EMPTY_STRING (VariableName)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsListEmpty (&ETagList->Listheader)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Caculate the total size we need to keep ETag list.
+ //
+ VarSize = ETagList->TotalSize + 1; // terminator character
+ VarData = AllocateZeroPool (VarSize);
+ if (VarData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Seeker = VarData;
+ Record = NULL;
+ List = GetFirstNode (&ETagList->Listheader);
+ while (!IsNull (&ETagList->Listheader, List)) {
+ Record = REDFISH_ETAG_RECORD_FROM_LIST (List);
+
+ StrSize = AsciiStrSize (Record->Uri);
+ CopyMem (Seeker, Record->Uri, StrSize);
+
+ Seeker += (StrSize - 1);
+ *Seeker = '|';
+ ++Seeker;
+
+ StrSize = AsciiStrSize (Record->ETag);
+ CopyMem (Seeker, Record->ETag, StrSize);
+
+ Seeker += (StrSize - 1);
+ *Seeker = '\n';
+
+ ++Seeker;
+
+ List = GetNextNode (&ETagList->Listheader, List);
+ }
+
+ *Seeker = '\0';
+
+ #if ETAG_DEBUG_ENABLED
+ DumpRawBuffer (VarData, VarSize);
+ #endif
+
+ ASSERT (((UINTN)Seeker - (UINTN)VarData + 1) == VarSize);
+
+ //
+ // Check if variable exists already. If yes, remove it first.
+ //
+ Status = GetVariable2 (
+ VariableName,
+ &gEfiCallerIdGuid,
+ (VOID *)&Data,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ FreePool (Data);
+ gRT->SetVariable (VariableName, &gEfiCallerIdGuid, VARIABLE_ATTRIBUTE_NV_BS, 0, NULL);
+ }
+
+ return gRT->SetVariable (VariableName, &gEfiCallerIdGuid, VARIABLE_ATTRIBUTE_NV_BS, VarSize, (VOID *)VarData);
+}
+
+/**
+ Read etag from UEFI variable if it exists.
+
+ @param[in] ETagList The list to be loaded.
+ @param[in] VariableName The UEFI variable name.
+
+ @retval EFI_SUCCESS All etag is read successfully.
+ @retval EFI_INVALID_PARAMETER VariableName or ETagList is NULL.
+ @retval EFI_NOT_FOUND No etag is found on UEFI variable.
+
+**/
+EFI_STATUS
+InitialETagList (
+ IN REDFISH_ETAG_LIST *ETagList,
+ IN EFI_STRING VariableName
+ )
+{
+ CHAR8 *VarData;
+ CHAR8 *UriPointer;
+ CHAR8 *ETagPointer;
+ CHAR8 *Seeker;
+ UINTN VariableSize;
+ EFI_STATUS Status;
+
+ if ((ETagList == NULL) || IS_EMPTY_STRING (VariableName)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if variable exists already.
+ //
+ Status = GetVariable2 (
+ VariableName,
+ &gEfiCallerIdGuid,
+ (VOID *)&VarData,
+ &VariableSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Seeker = VarData;
+ UriPointer = VarData;
+ ETagPointer = VarData;
+ while (*Seeker != '\0') {
+ //
+ // Find URI
+ //
+ Seeker = AsciiStrStr (UriPointer, "|");
+ if (Seeker == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a, data corrupted\n", __FUNCTION__));
+ Status = EFI_DEVICE_ERROR;
+ goto ON_ERROR;
+ }
+
+ *Seeker = '\0';
+ ETagPointer = ++Seeker;
+
+ //
+ // Find ETAG
+ //
+ Seeker = AsciiStrStr (ETagPointer, "\n");
+ if (Seeker == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a, data corrupted\n", __FUNCTION__));
+ Status = EFI_DEVICE_ERROR;
+ goto ON_ERROR;
+ }
+
+ *Seeker = '\0';
+
+ AddETagRecord (ETagList, UriPointer, ETagPointer);
+
+ UriPointer = ++Seeker;
+ }
+
+ #if ETAG_DEBUG_ENABLED
+ DumpETagList (ETagList, L"Initial ETag List from Variable");
+ #endif
+
+ Status = EFI_SUCCESS;
+
+ON_ERROR:
+
+ FreePool (VarData);
+
+ return Status;
+}
+
+/**
+ Get ETag string by given URI
+
+ @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance.
+ @param[in] Uri Target URI to search.
+ @param[out] ETag The ETag string to corresponding URI.
+
+ @retval EFI_SUCCESS The ETag is found successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter is given.
+
+**/
+EFI_STATUS
+RedfishETagGet (
+ IN EDKII_REDFISH_ETAG_PROTOCOL *This,
+ IN CHAR8 *Uri,
+ OUT CHAR8 **ETag
+ )
+{
+ REDFISH_ETAG_RECORD *Target;
+ REDFISH_ETAG_PRIVATE_DATA *Private;
+
+ if ((This == NULL) || IS_EMPTY_STRING (Uri) || (ETag == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This);
+
+ *ETag = NULL;
+
+ Target = FindETagRecord (&Private->ETagList.Listheader, Uri);
+ if (Target == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ *ETag = AllocateCopyPool (AsciiStrSize (Target->ETag), Target->ETag);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Keep ETag string which maps to given Uri.
+
+ @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance.
+ @param[in] Uri The target Uri which related to ETag.
+ @param[in] ETag The ETag to add. If ETag is NULL, the record of correspoonding URI will be removed.
+
+ @retval EFI_SUCCESS This handler has been stoped successfully.
+ @retval Others Some error happened.
+
+**/
+EFI_STATUS
+RedfishETagSet (
+ IN EDKII_REDFISH_ETAG_PROTOCOL *This,
+ IN CHAR8 *Uri,
+ IN CHAR8 *ETag OPTIONAL
+ )
+{
+ REDFISH_ETAG_RECORD *Target;
+ REDFISH_ETAG_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+
+ if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This);
+
+ Status = EFI_NOT_FOUND;
+ Target = FindETagRecord (&Private->ETagList.Listheader, Uri);
+ if (Target != NULL) {
+ //
+ // Remove old one and create new one.
+ //
+ Status = DeleteETagRecord (&Private->ETagList, Target);
+ }
+
+ //
+ // When ETag is NULL, it means that we want to remov this record.
+ //
+ if (ETag == NULL) {
+ return Status;
+ }
+
+ return AddETagRecord (&Private->ETagList, Uri, ETag);
+}
+
+/**
+ Refresh the ETag database and save database to variable.
+
+ @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance.
+
+ @retval EFI_SUCCESS This handler has been stoped successfully.
+ @retval Others Some error happened.
+
+**/
+EFI_STATUS
+RedfishETagFlush (
+ IN EDKII_REDFISH_ETAG_PROTOCOL *This
+ )
+{
+ REDFISH_ETAG_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This);
+
+ Status = SaveETagList (&Private->ETagList, Private->VariableName);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, save ETag list to variable: %s failed: %r\n", __FUNCTION__, Private->VariableName, Status));
+ }
+
+ return Status;
+}
+
+/**
+ Callback function executed when the ExitBootService event group is signaled.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[out] Context Pointer to the Context buffer
+
+**/
+VOID
+EFIAPI
+RedfishETagOnExitBootService (
+ IN EFI_EVENT Event,
+ OUT VOID *Context
+ )
+{
+ //
+ // Memory is about to be released. Keep list into variable.
+ //
+ RedfishETagFlush (&mRedfishETagPrivate->Protocol);
+}
+
+/**
+ Unloads an image.
+
+ @param[in] ImageHandle Handle that identifies the image to be unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+ @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishETagDriverUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+
+ if (mRedfishETagPrivate != NULL) {
+ Status = gBS->UninstallProtocolInterface (
+ mRedfishETagPrivate->ImageHandle,
+ &gEdkIIRedfishETagProtocolGuid,
+ (VOID *)&mRedfishETagPrivate->Protocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, can not uninstall gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status));
+ ASSERT (FALSE);
+ }
+
+ ReleaseETagList (&mRedfishETagPrivate->ETagList);
+
+ if (mRedfishETagPrivate->VariableName != NULL) {
+ FreePool (mRedfishETagPrivate->VariableName);
+ }
+
+ if (mRedfishETagPrivate->Event != NULL) {
+ gBS->CloseEvent (mRedfishETagPrivate->Event);
+ }
+
+ FreePool (mRedfishETagPrivate);
+ mRedfishETagPrivate = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// EDKII_REDFISH_ETAG_PROTOCOL.
+//
+EDKII_REDFISH_ETAG_PROTOCOL mRedfishETagProtocol = {
+ RedfishETagGet,
+ RedfishETagSet,
+ RedfishETagFlush
+};
+
+/**
+ This is the declaration of an EFI image entry point. This entry point is
+ the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
+ both device drivers and bus drivers.
+
+ @param[in] ImageHandle The firmware allocated handle for the UEFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval Others An unexpected error occurred.
+**/
+EFI_STATUS
+EFIAPI
+RedfishETagDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mRedfishETagPrivate = AllocateZeroPool (sizeof (REDFISH_ETAG_PRIVATE_DATA));
+ if (mRedfishETagPrivate == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InitializeListHead (&mRedfishETagPrivate->ETagList.Listheader);
+ mRedfishETagPrivate->VariableName = AllocateCopyPool (StrSize (ETAG_VARIABLE_NAME), ETAG_VARIABLE_NAME);
+ if (mRedfishETagPrivate->VariableName == NULL) {
+ goto ON_ERROR;
+ }
+
+ mRedfishETagPrivate->ImageHandle = ImageHandle;
+ CopyMem (&mRedfishETagPrivate->Protocol, &mRedfishETagProtocol, sizeof (EDKII_REDFISH_ETAG_PROTOCOL));
+
+ Status = gBS->InstallProtocolInterface (
+ &ImageHandle,
+ &gEdkIIRedfishETagProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ (VOID *)&mRedfishETagPrivate->Protocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, can not install gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status));
+ ASSERT (FALSE);
+ goto ON_ERROR;
+ }
+
+ //
+ // Create Exit Boot Service event.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ RedfishETagOnExitBootService,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &mRedfishETagPrivate->Event
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to register Exit Boot Service event.", __FUNCTION__));
+ goto ON_ERROR;
+ }
+
+ //
+ // Read existing record from variable.
+ //
+ Status = InitialETagList (&mRedfishETagPrivate->ETagList, mRedfishETagPrivate->VariableName);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "%a, Initial ETag List: %r\n", __FUNCTION__, Status));
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ RedfishETagDriverUnload (ImageHandle);
+
+ return Status;
+}
--
2.17.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [edk2-redfish-client][PATCH 2/8] RedfishClientPkg: Add EDKII ETag driver
2023-05-04 14:22 [edk2-redfish-client][PATCH 2/8] RedfishClientPkg: Add EDKII ETag driver Nickle Wang
@ 2023-05-05 0:55 ` Chang, Abner
[not found] ` <175C194407D29FBE.22266@groups.io>
1 sibling, 0 replies; 3+ messages in thread
From: Chang, Abner @ 2023-05-05 0:55 UTC (permalink / raw)
To: Nickle Wang, devel@edk2.groups.io; +Cc: Igor Kulchytskyy
[AMD Official Use Only - General]
Reviewed-by: Abner Chang <abner.chang@hpe.com>
> -----Original Message-----
> From: Nickle Wang <nicklew@nvidia.com>
> Sent: Thursday, May 4, 2023 10:22 PM
> To: devel@edk2.groups.io
> Cc: Chang, Abner <Abner.Chang@amd.com>; Igor Kulchytskyy
> <igork@ami.com>
> Subject: [edk2-redfish-client][PATCH 2/8] RedfishClientPkg: Add EDKII ETag
> driver
>
> Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
>
>
> Implement EDKII ETag protocol to manipulate ETag of HTTP content.
>
> Signed-off-by: Nickle Wang <nicklew@nvidia.com>
> Cc: Abner Chang <abner.chang@amd.com>
> Cc: Igor Kulchytskyy <igork@ami.com>
> ---
> .../RedfishETagDxe/RedfishETagDxe.inf | 45 +
> .../Protocol/EdkIIRedfishETagProtocol.h | 76 ++
> .../RedfishETagDxe/RedfishETagDxe.h | 70 ++
> .../RedfishETagDxe/RedfishETagDxe.c | 772 ++++++++++++++++++
> 4 files changed, 963 insertions(+)
> create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf
> create mode 100644
> RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h
> create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h
> create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c
>
> diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf
> b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf
> new file mode 100644
> index 00000000..e29a1045
> --- /dev/null
> +++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf
> @@ -0,0 +1,45 @@
> +## @file
> +#
> +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR> # #
> +SPDX-License-Identifier: BSD-2-Clause-Patent # ##
> +
> +[Defines]
> + INF_VERSION = 0x0001000b
> + BASE_NAME = RedfishETagDxe
> + FILE_GUID = F7BB0BB2-9796-485F-9F00-C0EB47E9F92B
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = RedfishETagDriverEntryPoint
> + UNLOAD_IMAGE = RedfishETagDriverUnload
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + RedfishPkg/RedfishPkg.dec
> + RedfishClientPkg/RedfishClientPkg.dec
> +
> +[Sources]
> + RedfishETagDxe.h
> + RedfishETagDxe.c
> +
> +[LibraryClasses]
> + BaseLib
> + BaseMemoryLib
> + DebugLib
> + MemoryAllocationLib
> + UefiLib
> + UefiBootServicesTableLib
> + UefiRuntimeServicesTableLib
> + UefiDriverEntryPoint
> +
> +[Protocols]
> + gEdkIIRedfishETagProtocolGuid ## PRODUCED ##
> +
> +[Guids]
> + gEfiEventExitBootServicesGuid ## CONSUMES ## Event
> +
> +[Depex]
> + TRUE
> diff --git a/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h
> b/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h
> new file mode 100644
> index 00000000..4e10965a
> --- /dev/null
> +++ b/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h
> @@ -0,0 +1,76 @@
> +/** @file
> + This file defines the EDKII_REDFISH_FEATURE_PROTOCOL interface.
> +
> + (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef EDKII_REDFISH_ETAG_PROTOCOL_H_
> +#define EDKII_REDFISH_ETAG_PROTOCOL_H_
> +
> +typedef struct _EDKII_REDFISH_ETAG_PROTOCOL
> +EDKII_REDFISH_ETAG_PROTOCOL;
> +
> +/**
> + Get ETag string by given URI
> +
> + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL
> instance.
> + @param[in] Uri Target URI to search.
> + @param[out] ETag The ETag string to corresponding URI.
> +
> + @retval EFI_SUCCESS The ETag is found successfully.
> + @retval EFI_INVALID_PARAMETER Invalid parameter is given.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_GET)(
> + IN EDKII_REDFISH_ETAG_PROTOCOL *This,
> + IN CHAR8 *Uri,
> + OUT CHAR8 **ETag
> + );
> +
> +/**
> + Keep ETag string which maps to given Uri.
> +
> + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL
> instance.
> + @param[in] Uri The target Uri which related to ETag.
> + @param[in] ETag The ETag to add. If ETag is NULL, the record of
> correspoonding URI will be removed.
> +
> + @retval EFI_SUCCESS This handler has been stoped successfully.
> + @retval Others Some error happened.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_SET)(
> + IN EDKII_REDFISH_ETAG_PROTOCOL *This,
> + IN CHAR8 *Uri,
> + IN CHAR8 *ETag
> + );
> +
> +/**
> + Refresh the ETag database and save database to variable.
> +
> + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL
> instance.
> +
> + @retval EFI_SUCCESS This handler has been stoped successfully.
> + @retval Others Some error happened.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_FLUSH)(
> + IN EDKII_REDFISH_ETAG_PROTOCOL *This
> + );
> +
> +struct _EDKII_REDFISH_ETAG_PROTOCOL {
> + EDKII_REDFISH_ETAG_PROTOCOL_GET Get;
> + EDKII_REDFISH_ETAG_PROTOCOL_SET Set;
> + EDKII_REDFISH_ETAG_PROTOCOL_FLUSH Flush;
> +};
> +
> +extern EFI_GUID gEdkIIRedfishETagProtocolGuid;
> +
> +#endif
> diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h
> b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h
> new file mode 100644
> index 00000000..6dffa9d7
> --- /dev/null
> +++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h
> @@ -0,0 +1,70 @@
> +/** @file
> + Common header file for RedfishETagDxe driver.
> +
> + (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef REDFISH_ETAG_DXE_H_
> +#define REDFISH_ETAG_DXE_H_
> +
> +#include <Uefi.h>
> +
> +//
> +// Libraries
> +//
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +
> +#include <Library/MemoryAllocationLib.h> #include
> +<Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiDriverEntryPoint.h> #include <Library/UefiLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +
> +#include <Protocol/EdkIIRedfishETagProtocol.h>
> +
> +#include <Guid/VariableFormat.h>
> +
> +#define ETAG_VARIABLE_NAME L"RedfishETag"
> +#define IS_EMPTY_STRING(a) ((a) == NULL || (a)[0] == '\0') #define
> +ETAG_DEBUG_ENABLED 0x00
> +
> +//
> +// Definition of REDFISH_ETAG_RECORD
> +//
> +typedef struct {
> + LIST_ENTRY List;
> + CHAR8 *Uri;
> + CHAR8 *ETag;
> + UINTN Size;
> +} REDFISH_ETAG_RECORD;
> +
> +#define REDFISH_ETAG_RECORD_FROM_LIST(a) BASE_CR (a,
> +REDFISH_ETAG_RECORD, List)
> +
> +//
> +// Definition of REDFISH_ETAG_LIST
> +//
> +typedef struct {
> + LIST_ENTRY Listheader;
> + UINTN TotalSize;
> + UINTN Count;
> +} REDFISH_ETAG_LIST;
> +
> +//
> +// Definition of REDFISH_ETAG_PRIVATE_DATA // typedef struct {
> + EFI_HANDLE ImageHandle;
> + REDFISH_ETAG_LIST ETagList;
> + EDKII_REDFISH_ETAG_PROTOCOL Protocol;
> + EFI_STRING VariableName;
> + EFI_EVENT Event;
> +} REDFISH_ETAG_PRIVATE_DATA;
> +
> +#define REDFISH_ETAG_PRIVATE_FROM_THIS(a) BASE_CR (a,
> +REDFISH_ETAG_PRIVATE_DATA, Protocol)
> +
> +#endif
> diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c
> b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c
> new file mode 100644
> index 00000000..af920afc
> --- /dev/null
> +++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c
> @@ -0,0 +1,772 @@
> +/** @file
> +
> + (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "RedfishETagDxe.h"
> +
> +REDFISH_ETAG_PRIVATE_DATA *mRedfishETagPrivate = NULL;
> +
> +/**
> + Release REDFISH_ETAG_RECORD resource
> +
> + @param[in] Record Pointer to REDFISH_ETAG_RECORD instance
> +
> + @retval EFI_SUCCESS REDFISH_ETAG_RECORD is released
> successfully.
> + @retval EFI_INVALID_PARAMETER Record is NULL
> +
> +**/
> +EFI_STATUS
> +ReleaseETagRecord (
> + IN REDFISH_ETAG_RECORD *Record
> + )
> +{
> + if (Record == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (Record->Uri != NULL) {
> + FreePool (Record->Uri);
> + }
> +
> + if (Record->ETag != NULL) {
> + FreePool (Record->ETag);
> + }
> +
> + FreePool (Record);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Create new Etag resource.
> +
> + @param[in] Uri The URI string matching to this ETAG.
> + @param[in] ETag ETAG string.
> +
> + @retval REDFISH_ETAG_RECORD * Pointer to newly created ETAG.
> + @retval NULL No memory available.
> +
> +**/
> +REDFISH_ETAG_RECORD *
> +NewETagRecord (
> + IN CHAR8 *Uri,
> + IN CHAR8 *ETag
> + )
> +{
> + REDFISH_ETAG_RECORD *NewRecord;
> + UINTN Size;
> +
> + if (IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (ETag)) {
> + return NULL;
> + }
> +
> + NewRecord = AllocateZeroPool (sizeof (REDFISH_ETAG_RECORD)); if
> + (NewRecord == NULL) {
> + return NULL;
> + }
> +
> + Size = AsciiStrSize (Uri);
> + NewRecord->Uri = AllocateCopyPool (Size, Uri); if (NewRecord->Uri ==
> + NULL) {
> + goto ON_ERROR;
> + }
> +
> + NewRecord->Size = Size;
> + Size = AsciiStrSize (ETag);
> + NewRecord->ETag = AllocateCopyPool (Size, ETag); if (NewRecord->ETag
> + == NULL) {
> + goto ON_ERROR;
> + }
> +
> + NewRecord->Size += Size;
> + return NewRecord;
> +
> +ON_ERROR:
> +
> + if (NewRecord != NULL) {
> + ReleaseETagRecord (NewRecord);
> + }
> +
> + return NULL;
> +}
> +
> +/**
> + Add new ETAG by given URI and ETAG string to specify List.
> +
> + @param[in] List Target ETAG list to add.
> + @param[in] Uri The URI string matching to this ETAG.
> + @param[in] ETag ETAG string.
> +
> + @retval EFI_SUCCESS ETAG recourd is added.
> + @retval Others Fail to add ETAG.
> +
> +**/
> +EFI_STATUS
> +AddETagRecord (
> + IN REDFISH_ETAG_LIST *List,
> + IN CHAR8 *Uri,
> + IN CHAR8 *ETag
> + )
> +{
> + REDFISH_ETAG_RECORD *NewRecord;
> +
> + if ((List == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (ETag)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + NewRecord = NewETagRecord (Uri, ETag); if (NewETagRecord == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + InsertTailList (&List->Listheader, &NewRecord->List); ++List->Count;
> + List->TotalSize += NewRecord->Size;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Delete an ETAG by given ETAG instance.
> +
> + @param[in] List Target ETAG list to be removed.
> + @param[in] Record Pointer to the instance to be deleted.
> +
> + @retval EFI_SUCCESS ETAG recourd is removed.
> + @retval Others Fail to add ETAG.
> +
> +**/
> +EFI_STATUS
> +DeleteETagRecord (
> + IN REDFISH_ETAG_LIST *List,
> + IN REDFISH_ETAG_RECORD *Record
> + )
> +{
> + if ((List == NULL) || (Record == NULL)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + RemoveEntryList (&Record->List);
> + --List->Count;
> + List->TotalSize -= Record->Size;
> +
> + return ReleaseETagRecord (Record);
> +}
> +
> +/**
> + Search on given ListHeader for given URI string.
> +
> + @param[in] ListHeader Target list to search.
> + @param[in] Uri Target URI to search.
> +
> + @retval REDFISH_ETAG_RECORD Target ETAG is found.
> + @retval NULL No ETAG with given URI is found.
> +
> +**/
> +REDFISH_ETAG_RECORD *
> +FindETagRecord (
> + IN LIST_ENTRY *ListHeader,
> + IN CHAR8 *Uri
> + )
> +{
> + LIST_ENTRY *List;
> + REDFISH_ETAG_RECORD *Record;
> +
> + if (IsListEmpty (ListHeader)) {
> + return NULL;
> + }
> +
> + Record = NULL;
> + List = GetFirstNode (ListHeader);
> + while (!IsNull (ListHeader, List)) {
> + Record = REDFISH_ETAG_RECORD_FROM_LIST (List);
> +
> + if (AsciiStrCmp (Record->Uri, Uri) == 0) {
> + return Record;
> + }
> +
> + List = GetNextNode (ListHeader, List); }
> +
> + return NULL;
> +}
> +
> +#if ETAG_DEBUG_ENABLED
> +
> +/**
> + Debug output the ETAG list.
> +
> + @param[in] ETagList Target list to dump
> + @param[in] Msg Debug message string.
> +
> + @retval EFI_SUCCESS Debug dump finished.
> + @retval EFI_INVALID_PARAMETER ETagList is NULL.
> +
> +**/
> +EFI_STATUS
> +DumpETagList (
> + IN REDFISH_ETAG_LIST *ETagList,
> + IN EFI_STRING Msg
> + )
> +{
> + LIST_ENTRY *List;
> + REDFISH_ETAG_RECORD *Record;
> +
> + if (ETagList == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (!IS_EMPTY_STRING (Msg)) {
> + DEBUG ((DEBUG_ERROR, "%s\n", Msg)); }
> +
> + if (IsListEmpty (&ETagList->Listheader)) {
> + DEBUG ((DEBUG_INFO, "ETag list is empty\n"));
> + return EFI_NOT_FOUND;
> + }
> +
> + DEBUG ((DEBUG_INFO, "Count: %d Total Size: %d\n", ETagList->Count,
> + ETagList->TotalSize)); Record = NULL;
> + List = GetFirstNode (&ETagList->Listheader);
> + while (!IsNull (&ETagList->Listheader, List)) {
> + Record = REDFISH_ETAG_RECORD_FROM_LIST (List);
> +
> + DEBUG ((DEBUG_INFO, "ETag: %a Uri: %a Size: %d\n", Record->ETag,
> + Record->Uri, Record->Size));
> +
> + List = GetNextNode (&ETagList->Listheader, List); }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Debug output raw data buffer.
> +
> + @param[in] Buffer Debug output data buffer.
> + @param[in] BufferSize The size of Buffer in byte.
> +
> + @retval EFI_SUCCESS Debug dump finished.
> + @retval EFI_INVALID_PARAMETER Buffer is NULL.
> +
> +**/
> +EFI_STATUS
> +DumpRawBuffer (
> + IN CHAR8 *Buffer,
> + IN UINTN BufferSize
> + )
> +{
> + UINTN Index;
> +
> + if (Buffer == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Index = 0;
> +
> + DEBUG ((DEBUG_ERROR, "Buffer size: %d\n", BufferSize)); while
> + (Buffer[Index] != '\0') {
> + DEBUG ((DEBUG_ERROR, "(%d) %c ", (Index + 1), Buffer[Index]));
> +
> + ++Index;
> + }
> +
> + DEBUG ((DEBUG_ERROR, "\n"));
> +
> + return EFI_SUCCESS;
> +}
> +
> +#endif
> +
> +/**
> + Release all ETag from list.
> +
> + @param[in] ETagList The list to be released.
> +
> + @retval EFI_SUCCESS All etag is released.
> + @retval EFI_INVALID_PARAMETER ETagList is NULL.
> +
> +**/
> +EFI_STATUS
> +ReleaseETagList (
> + IN REDFISH_ETAG_LIST *ETagList
> + )
> +{
> + LIST_ENTRY *List;
> + LIST_ENTRY *Next;
> + REDFISH_ETAG_RECORD *Record;
> +
> + if (ETagList == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (IsListEmpty (&ETagList->Listheader)) {
> + return EFI_SUCCESS;
> + }
> +
> + Record = NULL;
> + Next = NULL;
> + List = GetFirstNode (&ETagList->Listheader);
> + while (!IsNull (&ETagList->Listheader, List)) {
> + Record = REDFISH_ETAG_RECORD_FROM_LIST (List);
> + Next = GetNextNode (&ETagList->Listheader, List);
> +
> + DeleteETagRecord (ETagList, Record);
> +
> + List = Next;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Save etag in list to UEFI variable.
> +
> + @param[in] ETagList The list to be saved.
> + @param[in] VariableName The UEFI variable name.
> +
> + @retval EFI_SUCCESS All etag is saved.
> + @retval EFI_INVALID_PARAMETER VariableName or ETagList is NULL.
> +
> +**/
> +EFI_STATUS
> +SaveETagList (
> + IN REDFISH_ETAG_LIST *ETagList,
> + IN EFI_STRING VariableName
> + )
> +{
> + LIST_ENTRY *List;
> + REDFISH_ETAG_RECORD *Record;
> + CHAR8 *VarData;
> + VOID *Data;
> + CHAR8 *Seeker;
> + UINTN VarSize;
> + UINTN StrSize;
> + EFI_STATUS Status;
> +
> + if ((ETagList == NULL) || IS_EMPTY_STRING (VariableName)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (IsListEmpty (&ETagList->Listheader)) {
> + return EFI_SUCCESS;
> + }
> +
> + //
> + // Caculate the total size we need to keep ETag list.
> + //
> + VarSize = ETagList->TotalSize + 1; // terminator character VarData =
> + AllocateZeroPool (VarSize); if (VarData == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Seeker = VarData;
> + Record = NULL;
> + List = GetFirstNode (&ETagList->Listheader);
> + while (!IsNull (&ETagList->Listheader, List)) {
> + Record = REDFISH_ETAG_RECORD_FROM_LIST (List);
> +
> + StrSize = AsciiStrSize (Record->Uri);
> + CopyMem (Seeker, Record->Uri, StrSize);
> +
> + Seeker += (StrSize - 1);
> + *Seeker = '|';
> + ++Seeker;
> +
> + StrSize = AsciiStrSize (Record->ETag);
> + CopyMem (Seeker, Record->ETag, StrSize);
> +
> + Seeker += (StrSize - 1);
> + *Seeker = '\n';
> +
> + ++Seeker;
> +
> + List = GetNextNode (&ETagList->Listheader, List); }
> +
> + *Seeker = '\0';
> +
> + #if ETAG_DEBUG_ENABLED
> + DumpRawBuffer (VarData, VarSize);
> + #endif
> +
> + ASSERT (((UINTN)Seeker - (UINTN)VarData + 1) == VarSize);
> +
> + //
> + // Check if variable exists already. If yes, remove it first.
> + //
> + Status = GetVariable2 (
> + VariableName,
> + &gEfiCallerIdGuid,
> + (VOID *)&Data,
> + NULL
> + );
> + if (!EFI_ERROR (Status)) {
> + FreePool (Data);
> + gRT->SetVariable (VariableName, &gEfiCallerIdGuid,
> + VARIABLE_ATTRIBUTE_NV_BS, 0, NULL); }
> +
> + return gRT->SetVariable (VariableName, &gEfiCallerIdGuid,
> +VARIABLE_ATTRIBUTE_NV_BS, VarSize, (VOID *)VarData); }
> +
> +/**
> + Read etag from UEFI variable if it exists.
> +
> + @param[in] ETagList The list to be loaded.
> + @param[in] VariableName The UEFI variable name.
> +
> + @retval EFI_SUCCESS All etag is read successfully.
> + @retval EFI_INVALID_PARAMETER VariableName or ETagList is NULL.
> + @retval EFI_NOT_FOUND No etag is found on UEFI variable.
> +
> +**/
> +EFI_STATUS
> +InitialETagList (
> + IN REDFISH_ETAG_LIST *ETagList,
> + IN EFI_STRING VariableName
> + )
> +{
> + CHAR8 *VarData;
> + CHAR8 *UriPointer;
> + CHAR8 *ETagPointer;
> + CHAR8 *Seeker;
> + UINTN VariableSize;
> + EFI_STATUS Status;
> +
> + if ((ETagList == NULL) || IS_EMPTY_STRING (VariableName)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Check if variable exists already.
> + //
> + Status = GetVariable2 (
> + VariableName,
> + &gEfiCallerIdGuid,
> + (VOID *)&VarData,
> + &VariableSize
> + );
> + if (EFI_ERROR (Status)) {
> + return EFI_NOT_FOUND;
> + }
> +
> + Seeker = VarData;
> + UriPointer = VarData;
> + ETagPointer = VarData;
> + while (*Seeker != '\0') {
> + //
> + // Find URI
> + //
> + Seeker = AsciiStrStr (UriPointer, "|");
> + if (Seeker == NULL) {
> + DEBUG ((DEBUG_ERROR, "%a, data corrupted\n", __FUNCTION__));
> + Status = EFI_DEVICE_ERROR;
> + goto ON_ERROR;
> + }
> +
> + *Seeker = '\0';
> + ETagPointer = ++Seeker;
> +
> + //
> + // Find ETAG
> + //
> + Seeker = AsciiStrStr (ETagPointer, "\n");
> + if (Seeker == NULL) {
> + DEBUG ((DEBUG_ERROR, "%a, data corrupted\n", __FUNCTION__));
> + Status = EFI_DEVICE_ERROR;
> + goto ON_ERROR;
> + }
> +
> + *Seeker = '\0';
> +
> + AddETagRecord (ETagList, UriPointer, ETagPointer);
> +
> + UriPointer = ++Seeker;
> + }
> +
> + #if ETAG_DEBUG_ENABLED
> + DumpETagList (ETagList, L"Initial ETag List from Variable"); #endif
> +
> + Status = EFI_SUCCESS;
> +
> +ON_ERROR:
> +
> + FreePool (VarData);
> +
> + return Status;
> +}
> +
> +/**
> + Get ETag string by given URI
> +
> + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL
> instance.
> + @param[in] Uri Target URI to search.
> + @param[out] ETag The ETag string to corresponding URI.
> +
> + @retval EFI_SUCCESS The ETag is found successfully.
> + @retval EFI_INVALID_PARAMETER Invalid parameter is given.
> +
> +**/
> +EFI_STATUS
> +RedfishETagGet (
> + IN EDKII_REDFISH_ETAG_PROTOCOL *This,
> + IN CHAR8 *Uri,
> + OUT CHAR8 **ETag
> + )
> +{
> + REDFISH_ETAG_RECORD *Target;
> + REDFISH_ETAG_PRIVATE_DATA *Private;
> +
> + if ((This == NULL) || IS_EMPTY_STRING (Uri) || (ETag == NULL)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This);
> +
> + *ETag = NULL;
> +
> + Target = FindETagRecord (&Private->ETagList.Listheader, Uri); if
> + (Target == NULL) {
> + return EFI_NOT_FOUND;
> + }
> +
> + *ETag = AllocateCopyPool (AsciiStrSize (Target->ETag), Target->ETag);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Keep ETag string which maps to given Uri.
> +
> + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL
> instance.
> + @param[in] Uri The target Uri which related to ETag.
> + @param[in] ETag The ETag to add. If ETag is NULL, the record of
> correspoonding URI will be removed.
> +
> + @retval EFI_SUCCESS This handler has been stoped successfully.
> + @retval Others Some error happened.
> +
> +**/
> +EFI_STATUS
> +RedfishETagSet (
> + IN EDKII_REDFISH_ETAG_PROTOCOL *This,
> + IN CHAR8 *Uri,
> + IN CHAR8 *ETag OPTIONAL
> + )
> +{
> + REDFISH_ETAG_RECORD *Target;
> + REDFISH_ETAG_PRIVATE_DATA *Private;
> + EFI_STATUS Status;
> +
> + if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This);
> +
> + Status = EFI_NOT_FOUND;
> + Target = FindETagRecord (&Private->ETagList.Listheader, Uri); if
> + (Target != NULL) {
> + //
> + // Remove old one and create new one.
> + //
> + Status = DeleteETagRecord (&Private->ETagList, Target); }
> +
> + //
> + // When ETag is NULL, it means that we want to remov this record.
> + //
> + if (ETag == NULL) {
> + return Status;
> + }
> +
> + return AddETagRecord (&Private->ETagList, Uri, ETag); }
> +
> +/**
> + Refresh the ETag database and save database to variable.
> +
> + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL
> instance.
> +
> + @retval EFI_SUCCESS This handler has been stoped successfully.
> + @retval Others Some error happened.
> +
> +**/
> +EFI_STATUS
> +RedfishETagFlush (
> + IN EDKII_REDFISH_ETAG_PROTOCOL *This
> + )
> +{
> + REDFISH_ETAG_PRIVATE_DATA *Private;
> + EFI_STATUS Status;
> +
> + if (This == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This);
> +
> + Status = SaveETagList (&Private->ETagList, Private->VariableName);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a, save ETag list to variable: %s failed:
> + %r\n", __FUNCTION__, Private->VariableName, Status)); }
> +
> + return Status;
> +}
> +
> +/**
> + Callback function executed when the ExitBootService event group is
> signaled.
> +
> + @param[in] Event Event whose notification function is being invoked.
> + @param[out] Context Pointer to the Context buffer
> +
> +**/
> +VOID
> +EFIAPI
> +RedfishETagOnExitBootService (
> + IN EFI_EVENT Event,
> + OUT VOID *Context
> + )
> +{
> + //
> + // Memory is about to be released. Keep list into variable.
> + //
> + RedfishETagFlush (&mRedfishETagPrivate->Protocol); }
> +
> +/**
> + Unloads an image.
> +
> + @param[in] ImageHandle Handle that identifies the image to be
> unloaded.
> +
> + @retval EFI_SUCCESS The image has been unloaded.
> + @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image
> handle.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishETagDriverUnload (
> + IN EFI_HANDLE ImageHandle
> + )
> +{
> + EFI_STATUS Status;
> +
> + if (mRedfishETagPrivate != NULL) {
> + Status = gBS->UninstallProtocolInterface (
> + mRedfishETagPrivate->ImageHandle,
> + &gEdkIIRedfishETagProtocolGuid,
> + (VOID *)&mRedfishETagPrivate->Protocol
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a, can not uninstall
> gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status));
> + ASSERT (FALSE);
> + }
> +
> + ReleaseETagList (&mRedfishETagPrivate->ETagList);
> +
> + if (mRedfishETagPrivate->VariableName != NULL) {
> + FreePool (mRedfishETagPrivate->VariableName);
> + }
> +
> + if (mRedfishETagPrivate->Event != NULL) {
> + gBS->CloseEvent (mRedfishETagPrivate->Event);
> + }
> +
> + FreePool (mRedfishETagPrivate);
> + mRedfishETagPrivate = NULL;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +//
> +// EDKII_REDFISH_ETAG_PROTOCOL.
> +//
> +EDKII_REDFISH_ETAG_PROTOCOL mRedfishETagProtocol = {
> + RedfishETagGet,
> + RedfishETagSet,
> + RedfishETagFlush
> +};
> +
> +/**
> + This is the declaration of an EFI image entry point. This entry point
> +is
> + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers
> +including
> + both device drivers and bus drivers.
> +
> + @param[in] ImageHandle The firmware allocated handle for the UEFI
> image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval EFI_SUCCESS The operation completed successfully.
> + @retval Others An unexpected error occurred.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishETagDriverEntryPoint (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> +
> + mRedfishETagPrivate = AllocateZeroPool (sizeof
> + (REDFISH_ETAG_PRIVATE_DATA)); if (mRedfishETagPrivate == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + InitializeListHead (&mRedfishETagPrivate->ETagList.Listheader);
> + mRedfishETagPrivate->VariableName = AllocateCopyPool (StrSize
> + (ETAG_VARIABLE_NAME), ETAG_VARIABLE_NAME); if
> (mRedfishETagPrivate->VariableName == NULL) {
> + goto ON_ERROR;
> + }
> +
> + mRedfishETagPrivate->ImageHandle = ImageHandle; CopyMem
> + (&mRedfishETagPrivate->Protocol, &mRedfishETagProtocol, sizeof
> + (EDKII_REDFISH_ETAG_PROTOCOL));
> +
> + Status = gBS->InstallProtocolInterface (
> + &ImageHandle,
> + &gEdkIIRedfishETagProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + (VOID *)&mRedfishETagPrivate->Protocol
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a, can not install
> gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status));
> + ASSERT (FALSE);
> + goto ON_ERROR;
> + }
> +
> + //
> + // Create Exit Boot Service event.
> + //
> + Status = gBS->CreateEventEx (
> + EVT_NOTIFY_SIGNAL,
> + TPL_CALLBACK,
> + RedfishETagOnExitBootService,
> + NULL,
> + &gEfiEventExitBootServicesGuid,
> + &mRedfishETagPrivate->Event
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a: Fail to register Exit Boot Service event.",
> __FUNCTION__));
> + goto ON_ERROR;
> + }
> +
> + //
> + // Read existing record from variable.
> + //
> + Status = InitialETagList (&mRedfishETagPrivate->ETagList,
> + mRedfishETagPrivate->VariableName);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "%a, Initial ETag List: %r\n", __FUNCTION__,
> + Status)); }
> +
> + return EFI_SUCCESS;
> +
> +ON_ERROR:
> +
> + RedfishETagDriverUnload (ImageHandle);
> +
> + return Status;
> +}
> --
> 2.17.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [edk2-devel] [edk2-redfish-client][PATCH 2/8] RedfishClientPkg: Add EDKII ETag driver
[not found] ` <175C194407D29FBE.22266@groups.io>
@ 2023-05-05 1:14 ` Chang, Abner
0 siblings, 0 replies; 3+ messages in thread
From: Chang, Abner @ 2023-05-05 1:14 UTC (permalink / raw)
To: devel@edk2.groups.io, Chang, Abner, Nickle Wang; +Cc: Igor Kulchytskyy
[AMD Official Use Only - General]
Correct email address
Reviewed-by: Abner Chang <abner.chang@amd.com>
> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Chang,
> Abner via groups.io
> Sent: Friday, May 5, 2023 8:56 AM
> To: Nickle Wang <nicklew@nvidia.com>; devel@edk2.groups.io
> Cc: Igor Kulchytskyy <igork@ami.com>
> Subject: Re: [edk2-devel] [edk2-redfish-client][PATCH 2/8] RedfishClientPkg:
> Add EDKII ETag driver
>
> Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
>
>
> [AMD Official Use Only - General]
>
> Reviewed-by: Abner Chang <abner.chang@hpe.com>
>
> > -----Original Message-----
> > From: Nickle Wang <nicklew@nvidia.com>
> > Sent: Thursday, May 4, 2023 10:22 PM
> > To: devel@edk2.groups.io
> > Cc: Chang, Abner <Abner.Chang@amd.com>; Igor Kulchytskyy
> > <igork@ami.com>
> > Subject: [edk2-redfish-client][PATCH 2/8] RedfishClientPkg: Add EDKII
> > ETag driver
> >
> > Caution: This message originated from an External Source. Use proper
> > caution when opening attachments, clicking links, or responding.
> >
> >
> > Implement EDKII ETag protocol to manipulate ETag of HTTP content.
> >
> > Signed-off-by: Nickle Wang <nicklew@nvidia.com>
> > Cc: Abner Chang <abner.chang@amd.com>
> > Cc: Igor Kulchytskyy <igork@ami.com>
> > ---
> > .../RedfishETagDxe/RedfishETagDxe.inf | 45 +
> > .../Protocol/EdkIIRedfishETagProtocol.h | 76 ++
> > .../RedfishETagDxe/RedfishETagDxe.h | 70 ++
> > .../RedfishETagDxe/RedfishETagDxe.c | 772 ++++++++++++++++++
> > 4 files changed, 963 insertions(+)
> > create mode 100644
> RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf
> > create mode 100644
> > RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h
> > create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h
> > create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c
> >
> > diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf
> > b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf
> > new file mode 100644
> > index 00000000..e29a1045
> > --- /dev/null
> > +++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf
> > @@ -0,0 +1,45 @@
> > +## @file
> > +#
> > +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR> #
> > +#
> > +SPDX-License-Identifier: BSD-2-Clause-Patent # ##
> > +
> > +[Defines]
> > + INF_VERSION = 0x0001000b
> > + BASE_NAME = RedfishETagDxe
> > + FILE_GUID = F7BB0BB2-9796-485F-9F00-C0EB47E9F92B
> > + MODULE_TYPE = DXE_DRIVER
> > + VERSION_STRING = 1.0
> > + ENTRY_POINT = RedfishETagDriverEntryPoint
> > + UNLOAD_IMAGE = RedfishETagDriverUnload
> > +
> > +[Packages]
> > + MdePkg/MdePkg.dec
> > + MdeModulePkg/MdeModulePkg.dec
> > + RedfishPkg/RedfishPkg.dec
> > + RedfishClientPkg/RedfishClientPkg.dec
> > +
> > +[Sources]
> > + RedfishETagDxe.h
> > + RedfishETagDxe.c
> > +
> > +[LibraryClasses]
> > + BaseLib
> > + BaseMemoryLib
> > + DebugLib
> > + MemoryAllocationLib
> > + UefiLib
> > + UefiBootServicesTableLib
> > + UefiRuntimeServicesTableLib
> > + UefiDriverEntryPoint
> > +
> > +[Protocols]
> > + gEdkIIRedfishETagProtocolGuid ## PRODUCED ##
> > +
> > +[Guids]
> > + gEfiEventExitBootServicesGuid ## CONSUMES ## Event
> > +
> > +[Depex]
> > + TRUE
> > diff --git
> > a/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h
> > b/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h
> > new file mode 100644
> > index 00000000..4e10965a
> > --- /dev/null
> > +++ b/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h
> > @@ -0,0 +1,76 @@
> > +/** @file
> > + This file defines the EDKII_REDFISH_FEATURE_PROTOCOL interface.
> > +
> > + (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> > +
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef EDKII_REDFISH_ETAG_PROTOCOL_H_ #define
> > +EDKII_REDFISH_ETAG_PROTOCOL_H_
> > +
> > +typedef struct _EDKII_REDFISH_ETAG_PROTOCOL
> > +EDKII_REDFISH_ETAG_PROTOCOL;
> > +
> > +/**
> > + Get ETag string by given URI
> > +
> > + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL
> > instance.
> > + @param[in] Uri Target URI to search.
> > + @param[out] ETag The ETag string to corresponding URI.
> > +
> > + @retval EFI_SUCCESS The ETag is found successfully.
> > + @retval EFI_INVALID_PARAMETER Invalid parameter is given.
> > +
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_GET)(
> > + IN EDKII_REDFISH_ETAG_PROTOCOL *This,
> > + IN CHAR8 *Uri,
> > + OUT CHAR8 **ETag
> > + );
> > +
> > +/**
> > + Keep ETag string which maps to given Uri.
> > +
> > + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL
> > instance.
> > + @param[in] Uri The target Uri which related to ETag.
> > + @param[in] ETag The ETag to add. If ETag is NULL, the record of
> > correspoonding URI will be removed.
> > +
> > + @retval EFI_SUCCESS This handler has been stoped successfully.
> > + @retval Others Some error happened.
> > +
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_SET)(
> > + IN EDKII_REDFISH_ETAG_PROTOCOL *This,
> > + IN CHAR8 *Uri,
> > + IN CHAR8 *ETag
> > + );
> > +
> > +/**
> > + Refresh the ETag database and save database to variable.
> > +
> > + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL
> > instance.
> > +
> > + @retval EFI_SUCCESS This handler has been stoped successfully.
> > + @retval Others Some error happened.
> > +
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_FLUSH)(
> > + IN EDKII_REDFISH_ETAG_PROTOCOL *This
> > + );
> > +
> > +struct _EDKII_REDFISH_ETAG_PROTOCOL {
> > + EDKII_REDFISH_ETAG_PROTOCOL_GET Get;
> > + EDKII_REDFISH_ETAG_PROTOCOL_SET Set;
> > + EDKII_REDFISH_ETAG_PROTOCOL_FLUSH Flush;
> > +};
> > +
> > +extern EFI_GUID gEdkIIRedfishETagProtocolGuid;
> > +
> > +#endif
> > diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h
> > b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h
> > new file mode 100644
> > index 00000000..6dffa9d7
> > --- /dev/null
> > +++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h
> > @@ -0,0 +1,70 @@
> > +/** @file
> > + Common header file for RedfishETagDxe driver.
> > +
> > + (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> > +
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef REDFISH_ETAG_DXE_H_
> > +#define REDFISH_ETAG_DXE_H_
> > +
> > +#include <Uefi.h>
> > +
> > +//
> > +// Libraries
> > +//
> > +#include <Library/BaseLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/DebugLib.h>
> > +
> > +#include <Library/MemoryAllocationLib.h> #include
> > +<Library/UefiBootServicesTableLib.h>
> > +#include <Library/UefiDriverEntryPoint.h> #include
> > +<Library/UefiLib.h> #include <Library/UefiRuntimeServicesTableLib.h>
> > +
> > +#include <Protocol/EdkIIRedfishETagProtocol.h>
> > +
> > +#include <Guid/VariableFormat.h>
> > +
> > +#define ETAG_VARIABLE_NAME L"RedfishETag"
> > +#define IS_EMPTY_STRING(a) ((a) == NULL || (a)[0] == '\0') #define
> > +ETAG_DEBUG_ENABLED 0x00
> > +
> > +//
> > +// Definition of REDFISH_ETAG_RECORD
> > +//
> > +typedef struct {
> > + LIST_ENTRY List;
> > + CHAR8 *Uri;
> > + CHAR8 *ETag;
> > + UINTN Size;
> > +} REDFISH_ETAG_RECORD;
> > +
> > +#define REDFISH_ETAG_RECORD_FROM_LIST(a) BASE_CR (a,
> > +REDFISH_ETAG_RECORD, List)
> > +
> > +//
> > +// Definition of REDFISH_ETAG_LIST
> > +//
> > +typedef struct {
> > + LIST_ENTRY Listheader;
> > + UINTN TotalSize;
> > + UINTN Count;
> > +} REDFISH_ETAG_LIST;
> > +
> > +//
> > +// Definition of REDFISH_ETAG_PRIVATE_DATA // typedef struct {
> > + EFI_HANDLE ImageHandle;
> > + REDFISH_ETAG_LIST ETagList;
> > + EDKII_REDFISH_ETAG_PROTOCOL Protocol;
> > + EFI_STRING VariableName;
> > + EFI_EVENT Event;
> > +} REDFISH_ETAG_PRIVATE_DATA;
> > +
> > +#define REDFISH_ETAG_PRIVATE_FROM_THIS(a) BASE_CR (a,
> > +REDFISH_ETAG_PRIVATE_DATA, Protocol)
> > +
> > +#endif
> > diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c
> > b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c
> > new file mode 100644
> > index 00000000..af920afc
> > --- /dev/null
> > +++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c
> > @@ -0,0 +1,772 @@
> > +/** @file
> > +
> > + (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> > +
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include "RedfishETagDxe.h"
> > +
> > +REDFISH_ETAG_PRIVATE_DATA *mRedfishETagPrivate = NULL;
> > +
> > +/**
> > + Release REDFISH_ETAG_RECORD resource
> > +
> > + @param[in] Record Pointer to REDFISH_ETAG_RECORD instance
> > +
> > + @retval EFI_SUCCESS REDFISH_ETAG_RECORD is released
> > successfully.
> > + @retval EFI_INVALID_PARAMETER Record is NULL
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseETagRecord (
> > + IN REDFISH_ETAG_RECORD *Record
> > + )
> > +{
> > + if (Record == NULL) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (Record->Uri != NULL) {
> > + FreePool (Record->Uri);
> > + }
> > +
> > + if (Record->ETag != NULL) {
> > + FreePool (Record->ETag);
> > + }
> > +
> > + FreePool (Record);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Create new Etag resource.
> > +
> > + @param[in] Uri The URI string matching to this ETAG.
> > + @param[in] ETag ETAG string.
> > +
> > + @retval REDFISH_ETAG_RECORD * Pointer to newly created ETAG.
> > + @retval NULL No memory available.
> > +
> > +**/
> > +REDFISH_ETAG_RECORD *
> > +NewETagRecord (
> > + IN CHAR8 *Uri,
> > + IN CHAR8 *ETag
> > + )
> > +{
> > + REDFISH_ETAG_RECORD *NewRecord;
> > + UINTN Size;
> > +
> > + if (IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (ETag)) {
> > + return NULL;
> > + }
> > +
> > + NewRecord = AllocateZeroPool (sizeof (REDFISH_ETAG_RECORD)); if
> > + (NewRecord == NULL) {
> > + return NULL;
> > + }
> > +
> > + Size = AsciiStrSize (Uri);
> > + NewRecord->Uri = AllocateCopyPool (Size, Uri); if (NewRecord->Uri
> > + ==
> > + NULL) {
> > + goto ON_ERROR;
> > + }
> > +
> > + NewRecord->Size = Size;
> > + Size = AsciiStrSize (ETag);
> > + NewRecord->ETag = AllocateCopyPool (Size, ETag); if
> > + (NewRecord->ETag == NULL) {
> > + goto ON_ERROR;
> > + }
> > +
> > + NewRecord->Size += Size;
> > + return NewRecord;
> > +
> > +ON_ERROR:
> > +
> > + if (NewRecord != NULL) {
> > + ReleaseETagRecord (NewRecord);
> > + }
> > +
> > + return NULL;
> > +}
> > +
> > +/**
> > + Add new ETAG by given URI and ETAG string to specify List.
> > +
> > + @param[in] List Target ETAG list to add.
> > + @param[in] Uri The URI string matching to this ETAG.
> > + @param[in] ETag ETAG string.
> > +
> > + @retval EFI_SUCCESS ETAG recourd is added.
> > + @retval Others Fail to add ETAG.
> > +
> > +**/
> > +EFI_STATUS
> > +AddETagRecord (
> > + IN REDFISH_ETAG_LIST *List,
> > + IN CHAR8 *Uri,
> > + IN CHAR8 *ETag
> > + )
> > +{
> > + REDFISH_ETAG_RECORD *NewRecord;
> > +
> > + if ((List == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (ETag))
> {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + NewRecord = NewETagRecord (Uri, ETag); if (NewETagRecord == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + InsertTailList (&List->Listheader, &NewRecord->List);
> > + ++List->Count;
> > + List->TotalSize += NewRecord->Size;
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Delete an ETAG by given ETAG instance.
> > +
> > + @param[in] List Target ETAG list to be removed.
> > + @param[in] Record Pointer to the instance to be deleted.
> > +
> > + @retval EFI_SUCCESS ETAG recourd is removed.
> > + @retval Others Fail to add ETAG.
> > +
> > +**/
> > +EFI_STATUS
> > +DeleteETagRecord (
> > + IN REDFISH_ETAG_LIST *List,
> > + IN REDFISH_ETAG_RECORD *Record
> > + )
> > +{
> > + if ((List == NULL) || (Record == NULL)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + RemoveEntryList (&Record->List);
> > + --List->Count;
> > + List->TotalSize -= Record->Size;
> > +
> > + return ReleaseETagRecord (Record);
> > +}
> > +
> > +/**
> > + Search on given ListHeader for given URI string.
> > +
> > + @param[in] ListHeader Target list to search.
> > + @param[in] Uri Target URI to search.
> > +
> > + @retval REDFISH_ETAG_RECORD Target ETAG is found.
> > + @retval NULL No ETAG with given URI is found.
> > +
> > +**/
> > +REDFISH_ETAG_RECORD *
> > +FindETagRecord (
> > + IN LIST_ENTRY *ListHeader,
> > + IN CHAR8 *Uri
> > + )
> > +{
> > + LIST_ENTRY *List;
> > + REDFISH_ETAG_RECORD *Record;
> > +
> > + if (IsListEmpty (ListHeader)) {
> > + return NULL;
> > + }
> > +
> > + Record = NULL;
> > + List = GetFirstNode (ListHeader);
> > + while (!IsNull (ListHeader, List)) {
> > + Record = REDFISH_ETAG_RECORD_FROM_LIST (List);
> > +
> > + if (AsciiStrCmp (Record->Uri, Uri) == 0) {
> > + return Record;
> > + }
> > +
> > + List = GetNextNode (ListHeader, List); }
> > +
> > + return NULL;
> > +}
> > +
> > +#if ETAG_DEBUG_ENABLED
> > +
> > +/**
> > + Debug output the ETAG list.
> > +
> > + @param[in] ETagList Target list to dump
> > + @param[in] Msg Debug message string.
> > +
> > + @retval EFI_SUCCESS Debug dump finished.
> > + @retval EFI_INVALID_PARAMETER ETagList is NULL.
> > +
> > +**/
> > +EFI_STATUS
> > +DumpETagList (
> > + IN REDFISH_ETAG_LIST *ETagList,
> > + IN EFI_STRING Msg
> > + )
> > +{
> > + LIST_ENTRY *List;
> > + REDFISH_ETAG_RECORD *Record;
> > +
> > + if (ETagList == NULL) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (!IS_EMPTY_STRING (Msg)) {
> > + DEBUG ((DEBUG_ERROR, "%s\n", Msg)); }
> > +
> > + if (IsListEmpty (&ETagList->Listheader)) {
> > + DEBUG ((DEBUG_INFO, "ETag list is empty\n"));
> > + return EFI_NOT_FOUND;
> > + }
> > +
> > + DEBUG ((DEBUG_INFO, "Count: %d Total Size: %d\n", ETagList->Count,
> > + ETagList->TotalSize)); Record = NULL;
> > + List = GetFirstNode (&ETagList->Listheader);
> > + while (!IsNull (&ETagList->Listheader, List)) {
> > + Record = REDFISH_ETAG_RECORD_FROM_LIST (List);
> > +
> > + DEBUG ((DEBUG_INFO, "ETag: %a Uri: %a Size: %d\n", Record->ETag,
> > + Record->Uri, Record->Size));
> > +
> > + List = GetNextNode (&ETagList->Listheader, List); }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Debug output raw data buffer.
> > +
> > + @param[in] Buffer Debug output data buffer.
> > + @param[in] BufferSize The size of Buffer in byte.
> > +
> > + @retval EFI_SUCCESS Debug dump finished.
> > + @retval EFI_INVALID_PARAMETER Buffer is NULL.
> > +
> > +**/
> > +EFI_STATUS
> > +DumpRawBuffer (
> > + IN CHAR8 *Buffer,
> > + IN UINTN BufferSize
> > + )
> > +{
> > + UINTN Index;
> > +
> > + if (Buffer == NULL) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + Index = 0;
> > +
> > + DEBUG ((DEBUG_ERROR, "Buffer size: %d\n", BufferSize)); while
> > + (Buffer[Index] != '\0') {
> > + DEBUG ((DEBUG_ERROR, "(%d) %c ", (Index + 1), Buffer[Index]));
> > +
> > + ++Index;
> > + }
> > +
> > + DEBUG ((DEBUG_ERROR, "\n"));
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +#endif
> > +
> > +/**
> > + Release all ETag from list.
> > +
> > + @param[in] ETagList The list to be released.
> > +
> > + @retval EFI_SUCCESS All etag is released.
> > + @retval EFI_INVALID_PARAMETER ETagList is NULL.
> > +
> > +**/
> > +EFI_STATUS
> > +ReleaseETagList (
> > + IN REDFISH_ETAG_LIST *ETagList
> > + )
> > +{
> > + LIST_ENTRY *List;
> > + LIST_ENTRY *Next;
> > + REDFISH_ETAG_RECORD *Record;
> > +
> > + if (ETagList == NULL) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (IsListEmpty (&ETagList->Listheader)) {
> > + return EFI_SUCCESS;
> > + }
> > +
> > + Record = NULL;
> > + Next = NULL;
> > + List = GetFirstNode (&ETagList->Listheader);
> > + while (!IsNull (&ETagList->Listheader, List)) {
> > + Record = REDFISH_ETAG_RECORD_FROM_LIST (List);
> > + Next = GetNextNode (&ETagList->Listheader, List);
> > +
> > + DeleteETagRecord (ETagList, Record);
> > +
> > + List = Next;
> > + }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Save etag in list to UEFI variable.
> > +
> > + @param[in] ETagList The list to be saved.
> > + @param[in] VariableName The UEFI variable name.
> > +
> > + @retval EFI_SUCCESS All etag is saved.
> > + @retval EFI_INVALID_PARAMETER VariableName or ETagList is NULL.
> > +
> > +**/
> > +EFI_STATUS
> > +SaveETagList (
> > + IN REDFISH_ETAG_LIST *ETagList,
> > + IN EFI_STRING VariableName
> > + )
> > +{
> > + LIST_ENTRY *List;
> > + REDFISH_ETAG_RECORD *Record;
> > + CHAR8 *VarData;
> > + VOID *Data;
> > + CHAR8 *Seeker;
> > + UINTN VarSize;
> > + UINTN StrSize;
> > + EFI_STATUS Status;
> > +
> > + if ((ETagList == NULL) || IS_EMPTY_STRING (VariableName)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (IsListEmpty (&ETagList->Listheader)) {
> > + return EFI_SUCCESS;
> > + }
> > +
> > + //
> > + // Caculate the total size we need to keep ETag list.
> > + //
> > + VarSize = ETagList->TotalSize + 1; // terminator character VarData
> > + = AllocateZeroPool (VarSize); if (VarData == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + Seeker = VarData;
> > + Record = NULL;
> > + List = GetFirstNode (&ETagList->Listheader);
> > + while (!IsNull (&ETagList->Listheader, List)) {
> > + Record = REDFISH_ETAG_RECORD_FROM_LIST (List);
> > +
> > + StrSize = AsciiStrSize (Record->Uri);
> > + CopyMem (Seeker, Record->Uri, StrSize);
> > +
> > + Seeker += (StrSize - 1);
> > + *Seeker = '|';
> > + ++Seeker;
> > +
> > + StrSize = AsciiStrSize (Record->ETag);
> > + CopyMem (Seeker, Record->ETag, StrSize);
> > +
> > + Seeker += (StrSize - 1);
> > + *Seeker = '\n';
> > +
> > + ++Seeker;
> > +
> > + List = GetNextNode (&ETagList->Listheader, List); }
> > +
> > + *Seeker = '\0';
> > +
> > + #if ETAG_DEBUG_ENABLED
> > + DumpRawBuffer (VarData, VarSize);
> > + #endif
> > +
> > + ASSERT (((UINTN)Seeker - (UINTN)VarData + 1) == VarSize);
> > +
> > + //
> > + // Check if variable exists already. If yes, remove it first.
> > + //
> > + Status = GetVariable2 (
> > + VariableName,
> > + &gEfiCallerIdGuid,
> > + (VOID *)&Data,
> > + NULL
> > + );
> > + if (!EFI_ERROR (Status)) {
> > + FreePool (Data);
> > + gRT->SetVariable (VariableName, &gEfiCallerIdGuid,
> > + VARIABLE_ATTRIBUTE_NV_BS, 0, NULL); }
> > +
> > + return gRT->SetVariable (VariableName, &gEfiCallerIdGuid,
> > +VARIABLE_ATTRIBUTE_NV_BS, VarSize, (VOID *)VarData); }
> > +
> > +/**
> > + Read etag from UEFI variable if it exists.
> > +
> > + @param[in] ETagList The list to be loaded.
> > + @param[in] VariableName The UEFI variable name.
> > +
> > + @retval EFI_SUCCESS All etag is read successfully.
> > + @retval EFI_INVALID_PARAMETER VariableName or ETagList is NULL.
> > + @retval EFI_NOT_FOUND No etag is found on UEFI variable.
> > +
> > +**/
> > +EFI_STATUS
> > +InitialETagList (
> > + IN REDFISH_ETAG_LIST *ETagList,
> > + IN EFI_STRING VariableName
> > + )
> > +{
> > + CHAR8 *VarData;
> > + CHAR8 *UriPointer;
> > + CHAR8 *ETagPointer;
> > + CHAR8 *Seeker;
> > + UINTN VariableSize;
> > + EFI_STATUS Status;
> > +
> > + if ((ETagList == NULL) || IS_EMPTY_STRING (VariableName)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + //
> > + // Check if variable exists already.
> > + //
> > + Status = GetVariable2 (
> > + VariableName,
> > + &gEfiCallerIdGuid,
> > + (VOID *)&VarData,
> > + &VariableSize
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return EFI_NOT_FOUND;
> > + }
> > +
> > + Seeker = VarData;
> > + UriPointer = VarData;
> > + ETagPointer = VarData;
> > + while (*Seeker != '\0') {
> > + //
> > + // Find URI
> > + //
> > + Seeker = AsciiStrStr (UriPointer, "|");
> > + if (Seeker == NULL) {
> > + DEBUG ((DEBUG_ERROR, "%a, data corrupted\n", __FUNCTION__));
> > + Status = EFI_DEVICE_ERROR;
> > + goto ON_ERROR;
> > + }
> > +
> > + *Seeker = '\0';
> > + ETagPointer = ++Seeker;
> > +
> > + //
> > + // Find ETAG
> > + //
> > + Seeker = AsciiStrStr (ETagPointer, "\n");
> > + if (Seeker == NULL) {
> > + DEBUG ((DEBUG_ERROR, "%a, data corrupted\n", __FUNCTION__));
> > + Status = EFI_DEVICE_ERROR;
> > + goto ON_ERROR;
> > + }
> > +
> > + *Seeker = '\0';
> > +
> > + AddETagRecord (ETagList, UriPointer, ETagPointer);
> > +
> > + UriPointer = ++Seeker;
> > + }
> > +
> > + #if ETAG_DEBUG_ENABLED
> > + DumpETagList (ETagList, L"Initial ETag List from Variable"); #endif
> > +
> > + Status = EFI_SUCCESS;
> > +
> > +ON_ERROR:
> > +
> > + FreePool (VarData);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Get ETag string by given URI
> > +
> > + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL
> > instance.
> > + @param[in] Uri Target URI to search.
> > + @param[out] ETag The ETag string to corresponding URI.
> > +
> > + @retval EFI_SUCCESS The ETag is found successfully.
> > + @retval EFI_INVALID_PARAMETER Invalid parameter is given.
> > +
> > +**/
> > +EFI_STATUS
> > +RedfishETagGet (
> > + IN EDKII_REDFISH_ETAG_PROTOCOL *This,
> > + IN CHAR8 *Uri,
> > + OUT CHAR8 **ETag
> > + )
> > +{
> > + REDFISH_ETAG_RECORD *Target;
> > + REDFISH_ETAG_PRIVATE_DATA *Private;
> > +
> > + if ((This == NULL) || IS_EMPTY_STRING (Uri) || (ETag == NULL)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This);
> > +
> > + *ETag = NULL;
> > +
> > + Target = FindETagRecord (&Private->ETagList.Listheader, Uri); if
> > + (Target == NULL) {
> > + return EFI_NOT_FOUND;
> > + }
> > +
> > + *ETag = AllocateCopyPool (AsciiStrSize (Target->ETag),
> > + Target->ETag);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Keep ETag string which maps to given Uri.
> > +
> > + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL
> > instance.
> > + @param[in] Uri The target Uri which related to ETag.
> > + @param[in] ETag The ETag to add. If ETag is NULL, the record of
> > correspoonding URI will be removed.
> > +
> > + @retval EFI_SUCCESS This handler has been stoped successfully.
> > + @retval Others Some error happened.
> > +
> > +**/
> > +EFI_STATUS
> > +RedfishETagSet (
> > + IN EDKII_REDFISH_ETAG_PROTOCOL *This,
> > + IN CHAR8 *Uri,
> > + IN CHAR8 *ETag OPTIONAL
> > + )
> > +{
> > + REDFISH_ETAG_RECORD *Target;
> > + REDFISH_ETAG_PRIVATE_DATA *Private;
> > + EFI_STATUS Status;
> > +
> > + if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This);
> > +
> > + Status = EFI_NOT_FOUND;
> > + Target = FindETagRecord (&Private->ETagList.Listheader, Uri); if
> > + (Target != NULL) {
> > + //
> > + // Remove old one and create new one.
> > + //
> > + Status = DeleteETagRecord (&Private->ETagList, Target); }
> > +
> > + //
> > + // When ETag is NULL, it means that we want to remov this record.
> > + //
> > + if (ETag == NULL) {
> > + return Status;
> > + }
> > +
> > + return AddETagRecord (&Private->ETagList, Uri, ETag); }
> > +
> > +/**
> > + Refresh the ETag database and save database to variable.
> > +
> > + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL
> > instance.
> > +
> > + @retval EFI_SUCCESS This handler has been stoped successfully.
> > + @retval Others Some error happened.
> > +
> > +**/
> > +EFI_STATUS
> > +RedfishETagFlush (
> > + IN EDKII_REDFISH_ETAG_PROTOCOL *This
> > + )
> > +{
> > + REDFISH_ETAG_PRIVATE_DATA *Private;
> > + EFI_STATUS Status;
> > +
> > + if (This == NULL) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This);
> > +
> > + Status = SaveETagList (&Private->ETagList, Private->VariableName);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a, save ETag list to variable: %s failed:
> > + %r\n", __FUNCTION__, Private->VariableName, Status)); }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Callback function executed when the ExitBootService event group is
> > signaled.
> > +
> > + @param[in] Event Event whose notification function is being invoked.
> > + @param[out] Context Pointer to the Context buffer
> > +
> > +**/
> > +VOID
> > +EFIAPI
> > +RedfishETagOnExitBootService (
> > + IN EFI_EVENT Event,
> > + OUT VOID *Context
> > + )
> > +{
> > + //
> > + // Memory is about to be released. Keep list into variable.
> > + //
> > + RedfishETagFlush (&mRedfishETagPrivate->Protocol); }
> > +
> > +/**
> > + Unloads an image.
> > +
> > + @param[in] ImageHandle Handle that identifies the image to be
> > unloaded.
> > +
> > + @retval EFI_SUCCESS The image has been unloaded.
> > + @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image
> > handle.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishETagDriverUnload (
> > + IN EFI_HANDLE ImageHandle
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + if (mRedfishETagPrivate != NULL) {
> > + Status = gBS->UninstallProtocolInterface (
> > + mRedfishETagPrivate->ImageHandle,
> > + &gEdkIIRedfishETagProtocolGuid,
> > + (VOID *)&mRedfishETagPrivate->Protocol
> > + );
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a, can not uninstall
> > gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status));
> > + ASSERT (FALSE);
> > + }
> > +
> > + ReleaseETagList (&mRedfishETagPrivate->ETagList);
> > +
> > + if (mRedfishETagPrivate->VariableName != NULL) {
> > + FreePool (mRedfishETagPrivate->VariableName);
> > + }
> > +
> > + if (mRedfishETagPrivate->Event != NULL) {
> > + gBS->CloseEvent (mRedfishETagPrivate->Event);
> > + }
> > +
> > + FreePool (mRedfishETagPrivate);
> > + mRedfishETagPrivate = NULL;
> > + }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +//
> > +// EDKII_REDFISH_ETAG_PROTOCOL.
> > +//
> > +EDKII_REDFISH_ETAG_PROTOCOL mRedfishETagProtocol = {
> > + RedfishETagGet,
> > + RedfishETagSet,
> > + RedfishETagFlush
> > +};
> > +
> > +/**
> > + This is the declaration of an EFI image entry point. This entry
> > +point is
> > + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers
> > +including
> > + both device drivers and bus drivers.
> > +
> > + @param[in] ImageHandle The firmware allocated handle for the UEFI
> > image.
> > + @param[in] SystemTable A pointer to the EFI System Table.
> > +
> > + @retval EFI_SUCCESS The operation completed successfully.
> > + @retval Others An unexpected error occurred.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RedfishETagDriverEntryPoint (
> > + IN EFI_HANDLE ImageHandle,
> > + IN EFI_SYSTEM_TABLE *SystemTable
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + mRedfishETagPrivate = AllocateZeroPool (sizeof
> > + (REDFISH_ETAG_PRIVATE_DATA)); if (mRedfishETagPrivate == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + InitializeListHead (&mRedfishETagPrivate->ETagList.Listheader);
> > + mRedfishETagPrivate->VariableName = AllocateCopyPool (StrSize
> > + (ETAG_VARIABLE_NAME), ETAG_VARIABLE_NAME); if
> > (mRedfishETagPrivate->VariableName == NULL) {
> > + goto ON_ERROR;
> > + }
> > +
> > + mRedfishETagPrivate->ImageHandle = ImageHandle; CopyMem
> > + (&mRedfishETagPrivate->Protocol, &mRedfishETagProtocol, sizeof
> > + (EDKII_REDFISH_ETAG_PROTOCOL));
> > +
> > + Status = gBS->InstallProtocolInterface (
> > + &ImageHandle,
> > + &gEdkIIRedfishETagProtocolGuid,
> > + EFI_NATIVE_INTERFACE,
> > + (VOID *)&mRedfishETagPrivate->Protocol
> > + );
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a, can not install
> > gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status));
> > + ASSERT (FALSE);
> > + goto ON_ERROR;
> > + }
> > +
> > + //
> > + // Create Exit Boot Service event.
> > + //
> > + Status = gBS->CreateEventEx (
> > + EVT_NOTIFY_SIGNAL,
> > + TPL_CALLBACK,
> > + RedfishETagOnExitBootService,
> > + NULL,
> > + &gEfiEventExitBootServicesGuid,
> > + &mRedfishETagPrivate->Event
> > + );
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a: Fail to register Exit Boot Service
> > + event.",
> > __FUNCTION__));
> > + goto ON_ERROR;
> > + }
> > +
> > + //
> > + // Read existing record from variable.
> > + //
> > + Status = InitialETagList (&mRedfishETagPrivate->ETagList,
> > + mRedfishETagPrivate->VariableName);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_INFO, "%a, Initial ETag List: %r\n", __FUNCTION__,
> > + Status)); }
> > +
> > + return EFI_SUCCESS;
> > +
> > +ON_ERROR:
> > +
> > + RedfishETagDriverUnload (ImageHandle);
> > +
> > + return Status;
> > +}
> > --
> > 2.17.1
>
>
>
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2023-05-05 1:14 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-05-04 14:22 [edk2-redfish-client][PATCH 2/8] RedfishClientPkg: Add EDKII ETag driver Nickle Wang
2023-05-05 0:55 ` Chang, Abner
[not found] ` <175C194407D29FBE.22266@groups.io>
2023-05-05 1:14 ` [edk2-devel] " Chang, Abner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox