From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mx0b-002e3701.pphosted.com (mx0b-002e3701.pphosted.com [148.163.143.35]) by mx.groups.io with SMTP id smtpd.web11.29022.1635147718275387200 for ; Mon, 25 Oct 2021 00:42:02 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="body hash did not verify" header.i=@hpe.com header.s=pps0720 header.b=Yo20bKse; spf=temperror, err=temporary DNS error (domain: hpe.com, ip: 148.163.143.35, mailfrom: prvs=09325c280a=abner.chang@hpe.com) Received: from pps.filterd (m0150245.ppops.net [127.0.0.1]) by mx0b-002e3701.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 19P42tsl032004; Mon, 25 Oct 2021 07:41:44 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=hpe.com; h=from : to : cc : subject : date : message-id : mime-version : content-type : content-transfer-encoding; s=pps0720; bh=Lb657I3+7G5phMbtpBMTocDTrXV8fHp9R3SHZ42/Vqw=; b=Yo20bKsea8Fsegj7oeg4ZPDssu6lKq+zOtZy1tNNfp9v7fLub+qzIkQKjyPo0RjuT5rb PU9cpcXxhfrpIW1W485ZcQidLa6BesHJJj/C37i59KYFfP4eZPJpIdwXbHgG/z7dK/J2 z9CsLenDBsXymJVD/5SSC22TDy2vtDBLnVVBjU+cUVJTuhAT8e2Jh/XdBcmSCs6ZLXQ4 UvG7Z3K/uSe/0nrXiG1eQcD8d8RsT4jO4qIoRRt/bZLwRLXKCU+iBo+uRV23g/wLHugl I6ETh9pU27XLf8ipiENwTlOtmIxm5npdxM3lY0gwRX9+Nx1WsChmGfvxBkHGreFuoqzf BA== Received: from g4t3425.houston.hpe.com (g4t3425.houston.hpe.com [15.241.140.78]) by mx0b-002e3701.pphosted.com with ESMTP id 3bwbgfbpwh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 25 Oct 2021 07:41:44 +0000 Received: from g9t2301.houston.hpecorp.net (g9t2301.houston.hpecorp.net [16.220.97.129]) by g4t3425.houston.hpe.com (Postfix) with ESMTP id F0AA69A; Mon, 25 Oct 2021 07:41:43 +0000 (UTC) Received: from SAC2XFT1JT.asiapacific.hpqcorp.net (unknown [10.43.62.133]) by g9t2301.houston.hpecorp.net (Postfix) with ESMTP id E08C14C; Mon, 25 Oct 2021 07:41:42 +0000 (UTC) From: "Abner Chang" To: devel@edk2.groups.io Cc: nickle.wang@hpe.com, Liming Gao Subject: [PATCH 1/2] staging/RedfishClientPkg: Add EDKII ETag driver Date: Mon, 25 Oct 2021 15:41:41 +0800 Message-Id: <20211025074141.322192-1-abner.chang@hpe.com> X-Mailer: git-send-email 2.21.0.windows.1 MIME-Version: 1.0 X-Proofpoint-GUID: nZ9yExLdRo6T5NIS4FRBWo4i6S8T0qp4 X-Proofpoint-ORIG-GUID: nZ9yExLdRo6T5NIS4FRBWo4i6S8T0qp4 X-HPE-SCL: -1 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.182.1,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.0.607.475 definitions=2021-10-25_02,2021-10-25_01,2020-04-07_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 mlxlogscore=999 spamscore=0 bulkscore=0 priorityscore=1501 impostorscore=0 phishscore=0 clxscore=1015 mlxscore=0 malwarescore=0 adultscore=0 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2109230001 definitions=main-2110250045 X-MIME-Autoconverted: from 8bit to quoted-printable by mx0b-002e3701.pphosted.com id 19P42tsl032004 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Implement EDKII ETag protocol to manipulate ETag of HTTP content. Signed-off-by: Nickle Wang Cc: Abner Chang Cc: Liming Gao --- .../RedfishETagDxe/RedfishETagDxe.inf | 45 + .../Protocol/EdkIIRedfishETagProtocol.h | 76 ++ .../RedfishETagDxe/RedfishETagDxe.h | 70 ++ .../RedfishETagDxe/RedfishETagDxe.c | 774 ++++++++++++++++++ 4 files changed, 965 insertions(+) create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf create mode 100644 RedfishClientPkg/Include/Protocol/EdkIIRedfishETagPro= tocol.h create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf b/Redfish= ClientPkg/RedfishETagDxe/RedfishETagDxe.inf new file mode 100644 index 00000000000..4315b1eaa5f --- /dev/null +++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf @@ -0,0 +1,45 @@ +=EF=BB=BF## @file +# +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x0001000b + BASE_NAME =3D RedfishETagDxe + FILE_GUID =3D F7BB0BB2-9796-485F-9F00-C0EB47E9F92B + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D RedfishETagDriverEntryPoint + UNLOAD_IMAGE =3D 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 00000000000..3cbced44eb7 --- /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
+ + 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_PRO= TOCOL 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_PROTOCO= L 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 successf= ully. + @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_PROTOCO= L instance. + + @retval EFI_SUCCESS This handler has been stoped successf= ully. + @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/RedfishCl= ientPkg/RedfishETagDxe/RedfishETagDxe.h new file mode 100644 index 00000000000..c4465743133 --- /dev/null +++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h @@ -0,0 +1,70 @@ +=EF=BB=BF/** @file + Common header file for RedfishETagDxe driver. + + (C) Copyright 2021 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef REDFISH_ETAG_DXE_H_ +#define REDFISH_ETAG_DXE_H_ + +#include + +// +// Libraries +// +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#define ETAG_VARIABLE_NAME L"RedfishETag" +#define IS_EMPTY_STRING(a) ((a) =3D=3D NULL || (a)[0] =3D=3D '\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_RECOR= D, 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_PRIV= ATE_DATA, Protocol) + +#endif diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c b/RedfishCl= ientPkg/RedfishETagDxe/RedfishETagDxe.c new file mode 100644 index 00000000000..349175340d4 --- /dev/null +++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c @@ -0,0 +1,774 @@ +=EF=BB=BF/** @file + + (C) Copyright 2021 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "RedfishETagDxe.h" + +REDFISH_ETAG_PRIVATE_DATA *mRedfishETagPrivate =3D NULL; + +/** + Release REDFISH_ETAG_RECORD resource + + @param[in] Record Pointer to REDFISH_ETAG_RECORD instance + + @retval EFI_SUCCESS REDFISH_ETAG_RECORD is released succes= sfully. + @retval EFI_INVALID_PARAMETER Record is NULL + +**/ +EFI_STATUS +ReleaseETagRecord ( + IN REDFISH_ETAG_RECORD *Record + ) +{ + if (Record =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Record->Uri !=3D NULL) { + FreePool (Record->Uri); + } + + if (Record->ETag !=3D 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 =3D AllocateZeroPool (sizeof (REDFISH_ETAG_RECORD)); + if (NewRecord =3D=3D NULL) { + return NULL; + } + + Size =3D AsciiStrSize (Uri); + NewRecord->Uri =3D AllocateCopyPool (Size, Uri); + if (NewRecord->Uri =3D=3D NULL) { + goto ON_ERROR; + } + + NewRecord->Size =3D Size; + Size =3D AsciiStrSize (ETag); + NewRecord->ETag =3D AllocateCopyPool (Size, ETag); + if (NewRecord->ETag =3D=3D NULL) { + goto ON_ERROR; + } + + NewRecord->Size +=3D Size; + return NewRecord; + +ON_ERROR: + + if (NewRecord !=3D 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 =3D=3D NULL || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (ETag= )) { + return EFI_INVALID_PARAMETER; + } + + NewRecord =3D NewETagRecord (Uri, ETag); + if (NewETagRecord =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InsertTailList (&List->Listheader, &NewRecord->List); + ++List->Count; + List->TotalSize +=3D 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 =3D=3D NULL || Record =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList (&Record->List); + --List->Count; + List->TotalSize -=3D 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 =3D NULL; + List =3D GetFirstNode (ListHeader); + while (!IsNull (ListHeader, List)) { + Record =3D REDFISH_ETAG_RECORD_FROM_LIST (List); + + if (AsciiStrCmp (Record->Uri, Uri) =3D=3D 0) { + return Record; + } + + List =3D 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 =3D=3D 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, ETa= gList->TotalSize)); + Record =3D NULL; + List =3D GetFirstNode (&ETagList->Listheader); + while (!IsNull (&ETagList->Listheader, List)) { + Record =3D REDFISH_ETAG_RECORD_FROM_LIST (List); + + DEBUG ((DEBUG_INFO, "ETag: %a Uri: %a Size: %d\n", Record->ETag, Rec= ord->Uri, Record->Size)); + + List =3D 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Index =3D 0; + + DEBUG ((DEBUG_ERROR, "Buffer size: %d\n", BufferSize)); + while (Buffer[Index] !=3D '\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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (IsListEmpty (&ETagList->Listheader)) { + return EFI_SUCCESS; + } + + Record =3D NULL; + Next =3D NULL; + List =3D GetFirstNode (&ETagList->Listheader); + while (!IsNull (&ETagList->Listheader, List)) { + Record =3D REDFISH_ETAG_RECORD_FROM_LIST (List); + Next =3D GetNextNode (&ETagList->Listheader, List); + + DeleteETagRecord (ETagList, Record); + + List =3D 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 =3D=3D 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 =3D ETagList->TotalSize + 1; // terminator character + VarData =3D AllocateZeroPool (VarSize); + if (VarData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Seeker =3D VarData; + Record =3D NULL; + List =3D GetFirstNode (&ETagList->Listheader); + while (!IsNull (&ETagList->Listheader, List)) { + Record =3D REDFISH_ETAG_RECORD_FROM_LIST (List); + + StrSize =3D AsciiStrSize (Record->Uri); + CopyMem (Seeker, Record->Uri, StrSize); + + Seeker +=3D (StrSize - 1); + *Seeker =3D '|'; + ++Seeker; + + StrSize =3D AsciiStrSize (Record->ETag); + CopyMem (Seeker, Record->ETag, StrSize); + + Seeker +=3D (StrSize - 1); + *Seeker =3D '\n'; + + ++Seeker; + + List =3D GetNextNode (&ETagList->Listheader, List);; + } + + *Seeker =3D '\0'; + +#if ETAG_DEBUG_ENABLED + DumpRawBuffer (VarData, VarSize); +#endif + + ASSERT (((UINTN)Seeker - (UINTN)VarData + 1) =3D=3D VarSize); + + // + // Check if variable exists already. If yes, remove it first. + // + Status =3D GetVariable2 ( + VariableName, + &gEfiCallerIdGuid, + (VOID *)&Data, + NULL + ); + if (!EFI_ERROR (Status)) { + FreePool (Data); + gRT->SetVariable (VariableName, &gEfiCallerIdGuid, VARIABLE_ATTRIBUT= E_NV_BS, 0, NULL); + } + + + return gRT->SetVariable (VariableName, &gEfiCallerIdGuid, VARIABLE_ATT= RIBUTE_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 =3D=3D NULL || IS_EMPTY_STRING (VariableName)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check if variable exists already. + // + Status =3D GetVariable2 ( + VariableName, + &gEfiCallerIdGuid, + (VOID *)&VarData, + &VariableSize + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + Seeker =3D VarData; + UriPointer =3D VarData; + ETagPointer =3D VarData; + while (*Seeker !=3D '\0') { + + // + // Find URI + // + Seeker =3D AsciiStrStr (UriPointer, "|"); + if (Seeker =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a, data corrupted\n", __FUNCTION__)); + Status =3D EFI_DEVICE_ERROR; + goto ON_ERROR; + } + + *Seeker =3D '\0'; + ETagPointer =3D ++Seeker; + + // + // Find ETAG + // + Seeker =3D AsciiStrStr (ETagPointer, "\n"); + if (Seeker =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a, data corrupted\n", __FUNCTION__)); + Status =3D EFI_DEVICE_ERROR; + goto ON_ERROR; + } + + *Seeker =3D '\0'; + + AddETagRecord (ETagList, UriPointer, ETagPointer); + + UriPointer =3D ++Seeker; + } + +#if ETAG_DEBUG_ENABLED + DumpETagList (ETagList, L"Initial ETag List from Variable"); +#endif + + Status =3D EFI_SUCCESS; + +ON_ERROR: + + FreePool (VarData); + + return Status; +} + +/** + Get ETag string by given URI + + @param[in] This Pointer to EDKII_REDFISH_ETAG_PRO= TOCOL 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 =3D=3D NULL || IS_EMPTY_STRING (Uri) || ETag =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Private =3D REDFISH_ETAG_PRIVATE_FROM_THIS (This); + + *ETag =3D NULL; + + Target =3D FindETagRecord (&Private->ETagList.Listheader, Uri); + if (Target =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + *ETag =3D 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_PROTOCO= L 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 successf= ully. + @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 =3D=3D NULL || IS_EMPTY_STRING (Uri)) { + return EFI_INVALID_PARAMETER; + } + + Private =3D REDFISH_ETAG_PRIVATE_FROM_THIS (This); + + Status =3D EFI_NOT_FOUND; + Target =3D FindETagRecord (&Private->ETagList.Listheader, Uri); + if (Target !=3D NULL) { + // + // Remove old one and create new one. + // + Status =3D DeleteETagRecord (&Private->ETagList, Target); + } + + // + // When ETag is NULL, it means that we want to remov this record. + // + if (ETag =3D=3D 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_PROTOCO= L instance. + + @retval EFI_SUCCESS This handler has been stoped successf= ully. + @retval Others Some error happened. + +**/ +EFI_STATUS +RedfishETagFlush ( + IN EDKII_REDFISH_ETAG_PROTOCOL *This + ) +{ + REDFISH_ETAG_PRIVATE_DATA *Private; + EFI_STATUS Status; + + if (This =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Private =3D REDFISH_ETAG_PRIVATE_FROM_THIS (This); + + Status =3D 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 sig= naled. + + @param[in] Event Event whose notification function is being invok= ed. + @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 !=3D NULL) { + + Status =3D gBS->UninstallProtocolInterface ( + mRedfishETagPrivate->ImageHandle, + &gEdkIIRedfishETagProtocolGuid, + (VOID*)&mRedfishETagPrivate->Protocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, can not uninstall gEdkIIRedfishETagProto= colGuid: %r\n", __FUNCTION__, Status)); + ASSERT (FALSE); + } + + ReleaseETagList (&mRedfishETagPrivate->ETagList); + + if (mRedfishETagPrivate->VariableName !=3D NULL) { + FreePool (mRedfishETagPrivate->VariableName); + } + + if (mRedfishETagPrivate->Event !=3D NULL) { + gBS->CloseEvent (mRedfishETagPrivate->Event); + } + + FreePool (mRedfishETagPrivate); + mRedfishETagPrivate =3D NULL; + } + + + return EFI_SUCCESS; +} + +// +// EDKII_REDFISH_ETAG_PROTOCOL. +// +EDKII_REDFISH_ETAG_PROTOCOL mRedfishETagProtocol =3D { + 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 incl= uding + both device drivers and bus drivers. + + @param[in] ImageHandle The firmware allocated handle for the UE= FI 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 =3D AllocateZeroPool (sizeof (REDFISH_ETAG_PRIVATE= _DATA)); + if (mRedfishETagPrivate =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&mRedfishETagPrivate->ETagList.Listheader); + mRedfishETagPrivate->VariableName =3D AllocateCopyPool (StrSize (ETAG_= VARIABLE_NAME), ETAG_VARIABLE_NAME); + if (mRedfishETagPrivate->VariableName =3D=3D NULL) { + goto ON_ERROR; + } + + mRedfishETagPrivate->ImageHandle =3D ImageHandle; + CopyMem (&mRedfishETagPrivate->Protocol, &mRedfishETagProtocol, sizeof= (EDKII_REDFISH_ETAG_PROTOCOL)); + + Status =3D gBS->InstallProtocolInterface ( + &ImageHandle, + &gEdkIIRedfishETagProtocolGuid, + EFI_NATIVE_INTERFACE, + (VOID*)&mRedfishETagPrivate->Protocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, can not install gEdkIIRedfishETagProtocolG= uid: %r\n", __FUNCTION__, Status)); + ASSERT (FALSE); + goto ON_ERROR; + } + + // + // Create Exit Boot Service event. + // + Status =3D 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 =3D InitialETagList (&mRedfishETagPrivate->ETagList, mRedfishET= agPrivate->VariableName); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a, Initial ETag List: %r\n", __FUNCTION__, Sta= tus)); + } + + return EFI_SUCCESS; + +ON_ERROR: + + RedfishETagDriverUnload (ImageHandle); + + return Status; +} --=20 2.21.0.windows.1