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.web12.14834.1658885905291338878 for ; Tue, 26 Jul 2022 18:38:25 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@hpe.com header.s=pps0720 header.b=iK7ZVcTH; spf=permerror, err=parse error for token &{10 18 %{ir}.%{v}.%{d}.spf.has.pphosted.com}: invalid domain name (domain: hpe.com, ip: 148.163.143.35, mailfrom: prvs=0207a15765=nickle.wang@hpe.com) Received: from pps.filterd (m0134424.ppops.net [127.0.0.1]) by mx0b-002e3701.pphosted.com (8.17.1.5/8.17.1.5) with ESMTP id 26R1SnHD005126; Wed, 27 Jul 2022 01:38:22 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=hpe.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pps0720; bh=urRuDz20gHf+PdgJunx4zXB//nHtGrgOt33lgmcipUM=; b=iK7ZVcTH1x9ygZSSkRg7WMpJrvXe2/O+hnWLgUPRjTodAngPUZzT1j1ST0u0lYhPVHAv ziNKHVqVy7wYpLWJ0/mo+vI9yS7Obe/ejXYZQs/CsZzaq/7eoplplm/9x9ZDC2VF4ULA 5hHnqtRg92BnJu71DrFzxggEguu1vXrD1rUJCbGa7bAwvzaMuqO4UoWjt23Eu8J7TbFI 03N0870sirGiW5qog5c2ioyJJFzNG4+nh5fBrF9U96g1TVAWBuzR6kqDlMVEKX+xUVqH aUPCWgpaizAqW91rCY3gxaLJrhR16SWNnssDKfFnr8exvI+rD1fwPGjcCu5NSjaXfRUL Fg== Received: from p1lg14879.it.hpe.com (p1lg14879.it.hpe.com [16.230.97.200]) by mx0b-002e3701.pphosted.com (PPS) with ESMTPS id 3hjuqmr2d0-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 27 Jul 2022 01:38:21 +0000 Received: from p1lg14885.dc01.its.hpecorp.net (unknown [10.119.18.236]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by p1lg14879.it.hpe.com (Postfix) with ESMTPS id C5420132D1; Wed, 27 Jul 2022 01:38:20 +0000 (UTC) Received: from WAFM3XJD5N.asiapacific.hpqcorp.net (unknown [16.231.227.36]) by p1lg14885.dc01.its.hpecorp.net (Postfix) with ESMTP id 6930880561B; Wed, 27 Jul 2022 01:38:19 +0000 (UTC) From: "Nickle Wang" To: devel@edk2.groups.io Cc: Abner Chang , Yang Atom , Nick Ramirez Subject: [edk2-staging][PATCH v3 10/15] edk2-staging/RedfishClientPkg: Update Redfish feature utility library Date: Wed, 27 Jul 2022 09:37:57 +0800 Message-Id: <20220727013802.247-11-nickle.wang@hpe.com> X-Mailer: git-send-email 2.32.0.windows.2 In-Reply-To: <20220727013802.247-1-nickle.wang@hpe.com> References: <20220727013802.247-1-nickle.wang@hpe.com> MIME-Version: 1.0 X-Proofpoint-GUID: Mz0rA1w1pHY1H59zkoTNy1ciPsInknoA X-Proofpoint-ORIG-GUID: Mz0rA1w1pHY1H59zkoTNy1ciPsInknoA X-HPE-SCL: -1 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.883,Hydra:6.0.517,FMLib:17.11.122.1 definitions=2022-07-26_07,2022-07-26_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 suspectscore=0 priorityscore=1501 lowpriorityscore=0 spamscore=0 mlxlogscore=999 bulkscore=0 adultscore=0 impostorscore=0 mlxscore=0 malwarescore=0 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2206140000 definitions=main-2207270002 Content-Transfer-Encoding: 8bit Update Redfish feature utility library in order to support array type of resource. Some helper functions are introduced to get Redfish data. Also expose RedfishCsCommon.h so that feature utility library can work with Redfish C data structure without redundant structure conversion. Signed-off-by: Nickle Wang Cc: Abner Chang Cc: Yang Atom Cc: Nick Ramirez --- .../Library/RedfishFeatureUtilityLib.h | 756 +++- .../RedfishJsonStructure/RedfishCsCommon.h | 14 + .../RedfishFeatureUtilityInternal.h | 16 +- .../RedfishFeatureUtilityLib.c | 3662 +++++++++++++---- .../RedfishFeatureUtilityLib.inf | 20 +- 5 files changed, 3470 insertions(+), 998 deletions(-) create mode 100644 RedfishClientPkg/Include/RedfishJsonStructure/RedfishCsCommon.h diff --git a/RedfishClientPkg/Include/Library/RedfishFeatureUtilityLib.h b/RedfishClientPkg/Include/Library/RedfishFeatureUtilityLib.h index 50ff82c70f..1325976d8c 100644 --- a/RedfishClientPkg/Include/Library/RedfishFeatureUtilityLib.h +++ b/RedfishClientPkg/Include/Library/RedfishFeatureUtilityLib.h @@ -1,7 +1,7 @@ /** @file This file defines the Redfish Feature Utility Library interface. - (C) Copyright 2021 Hewlett Packard Enterprise Development LP
+ (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -10,8 +10,9 @@ #ifndef REDFISH_FEATURE_UTILITY_LIB_H_ #define REDFISH_FEATURE_UTILITY_LIB_H_ -#include -#include +#include +#include +#include // // Definition of REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG @@ -31,10 +32,10 @@ typedef struct { /** - Read redfish resource by given resource path. + Read redfish resource by given resource URI. @param[in] Service Redfish srvice instacne to make query. - @param[in] ResourcePath Target resource path. + @param[in] ResourceUri Target resource URI. @param[out] Response HTTP response from redfish service. @retval EFI_SUCCESS Resrouce is returned successfully. @@ -42,12 +43,34 @@ typedef struct { **/ EFI_STATUS -GetResourceByPath ( +GetResourceByUri ( IN REDFISH_SERVICE *Service, - IN CHAR8 *ResourcePath, + IN EFI_STRING ResourceUri, OUT REDFISH_RESPONSE *Response ); +/** + + Check if this is the Redpath array. Usually the Redpath array represents + the collection member. Return + + @param[in] ConfigureLang The Redpath to check + @param[out] ArraySignatureOpen String to the open of array signature. + @param[out] ArraySignatureClose String to the close of array signature. + + @retval EFI_SUCCESS Index is found. + @retval EFI_NOT_FOUND The non-array configure language string is retured. + @retval EFI_INVALID_PARAMETER The format of input ConfigureLang is wrong. + @retval Others Errors occur. + +**/ +EFI_STATUS +IsRedpathArray ( + IN EFI_STRING ConfigureLang, + OUT EFI_STRING *ArraySignatureOpen, + OUT EFI_STRING *ArraySignatureClose + ); + /** Search HII database with given Configure Language pattern. Data is handled and @@ -72,76 +95,142 @@ RedfishFeatureGetUnifiedArrayTypeConfigureLang ( /** - Get array key by parsing the URI. + Clone the configure language list. - @param[in] Uri URI with array key. - @param[out] ArrayKey Array key in given URI string. + @param[in] ConfigureLangList The source REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST. + @param[out] DestConfigureLangList The destination REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST. - @retval EFI_SUCCESS Array key is found. - @retval Others Errors occur. + @retval EFI_SUCCESS REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST is copied. + @retval Others Errors occur. **/ EFI_STATUS -GetArraykeyFromUri ( - IN CHAR8 *Uri, - OUT CHAR8 **ArrayKey +CopyConfiglanguageList ( + IN REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST *SourceConfigureLangList, + OUT REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST *DestConfigureLangList ); /** - Keep configure language with given key in UEFI variable. + Get number of node from the string. Node is seperated by '/'. - @param[in] Schema Schema name. - @param[in] Version Schema version. - @param[in] Key Key string. - @param[in] ConfigureLangIndex Index value. + @param[in] NodeString The node string to parse. - @retval EFI_SUCCESS Data is saved in UEFI variable. - @retval Others Errors occur. + @retval UINTN Number of nodes in the string. + +**/ +UINTN +GetNumberOfRedpathNodes ( + IN EFI_STRING NodeString + ); + +/** + + Get the node string by index + + @param[in] NodeString The node string to parse. + @param[in] Index Index of the node. + @param[out] EndOfNodePtr Pointer to receive the poitner to + the last character of node string. + + @retval EFI_STRING the begining of the node string. + +**/ +EFI_STRING +GetRedpathNodeByIndex ( + IN EFI_STRING NodeString, + IN UINTN Index, + OUT EFI_STRING *EndOfNodePtr OPTIONAL + ); + +/** + + Find array index from given configure language string. + + @param[in] ConfigureLang Configure language string to parse. + @param[out] UnifiedConfigureLang The configure language in array. + @param[out] Index The array index number. + + @retval EFI_SUCCESS Index is found. + @retval EFI_NOT_FOUND The non-array configure language string is retured. + @retval EFI_INVALID_PARAMETER The format of input ConfigureLang is wrong. + @retval Others Errors occur. **/ EFI_STATUS -SetConfigureLangWithkey ( - IN CHAR8 *Schema, - IN CHAR8 *Version, - IN CHAR8 *Key, - IN UINTN ConfigureLangIndex +GetArrayIndexFromArrayTypeConfigureLang ( + IN CHAR16 *ConfigureLang, + OUT CHAR16 **UnifiedConfigureLang, + OUT UINTN *Index ); /** - Find configure language with input key string. + Clone the configure language list. + + @param[in] ConfigureLang The pointer to configuration language. - @param[in] Schema Schema name. - @param[in] Version Schema version. - @param[in] Property Property name. - @param[in] Key Key string. + @retval UINTN The index of collection member instance. + Value of 0 means no instance is found. +**/ +UINTN +ConfiglanguageGetInstanceIndex ( + IN EFI_STRING ConfigureLang + ); - @retval CHAR16 * Corresponding configure langauge - @retval NULL No configure language is found +/** + + Destroy the configure language list. + + @param[in] ConfigureLangList The REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST + instance to destroy. + + @retval EFI_SUCCESS REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST is copied. + @retval Others Errors occur. **/ -CHAR16 * -GetConfigureLangByKey ( - IN CHAR8 *Schema, - IN CHAR8 *Version, - IN CHAR8 *Property, - IN CHAR8 *Key +EFI_STATUS +DestroyConfiglanguageList ( + IN REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST *ConfigureLangList ); /** - Convert HII string value to string value in JSON format. + Set the node instance. - @param[in] HiiStringValue String in HII format. + @param[in] DestConfigLang Pointer to the node's configure language string. + The memory pointed by ConfigLang must be allocated + through memory allocation interface. Becasue we will replace + the pointer in this function. + @param[in] MaxtLengthConfigLang The maximum length of ConfigLang. + @param[in] ConfigLangInstance Pointer to Collection member instance. - @retval CHAR8 * String in JSON format. - @retval NULL Errors occur. + @retval EFI_SUCCESS The instance is inserted to the configure language. + @retval Others Errors occur. **/ -CHAR8 * -ConvertHiiStringValueToJsonStringValue ( - IN EFI_STRING HiiStringValue +EFI_STATUS +SetResourceConfigLangMemberInstance ( + IN EFI_STRING *DestConfigLang, + IN UINTN MaxtLengthConfigLang, + IN REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG *ConfigLangInstance + ); + +/** + + Get array key by parsing the URI. + + @param[in] Uri URI with array key. + @param[out] ArrayKey Array key in given URI string. + + @retval EFI_SUCCESS Array key is found. + @retval Others Errors occur. + +**/ +EFI_STATUS +GetArraykeyFromUri ( + IN CHAR8 *Uri, + OUT CHAR8 **ArrayKey ); /** @@ -209,125 +298,157 @@ ApplyFeatureSettingsBooleanType ( /** - Create HTTP payload and send them to redfish service with POST method. + Apply property value to UEFI HII database in vague type. - @param[in] Service Redfish service. - @param[in] TargetPayload Target payload - @param[in] Json Data in JSON format. - @param[out] Location Returned location string from Redfish service. - @param[out] Etag Returned ETAG string from Redfish service. + @param[in] Schema Property schema. + @param[in] Version Property schema version. + @param[in] ConfigureLang Configure language refers to this property. + @param[in] VagueValuePtr Pointer of vague values to to set. + @param[in] NumVagueValues Number of vague values. - @retval EFI_SUCCESS Data is sent to redfish service successfully. + @retval EFI_SUCCESS New value is applied successfully. @retval Others Errors occur. **/ EFI_STATUS -CreatePayloadToPostResource ( - IN REDFISH_SERVICE *Service, - IN REDFISH_PAYLOAD *TargetPayload, - IN CHAR8 *Json, - OUT CHAR8 **Location, - OUT CHAR8 **Etag +ApplyFeatureSettingsVagueType ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING ConfigureLang, + IN RedfishCS_EmptyProp_KeyValue *VagueValuePtr, + IN UINT32 NumberOfVagueValues ); /** - Create HTTP payload and send them to redfish service with PATCH method. + Apply property value to UEFI HII database in string array type. - @param[in] Service Redfish service. - @param[in] TargetPayload Target payload - @param[in] Json Data in JSON format. - @param[out] Etag Returned ETAG string from Redfish service. + @param[in] Schema Property schema. + @param[in] Version Property schema version. + @param[in] ConfigureLang Configure language refers to this property. + @param[in] ArrayHead Head of array value. - @retval EFI_SUCCESS Data is sent to redfish service successfully. + @retval EFI_SUCCESS New value is applied successfully. @retval Others Errors occur. **/ EFI_STATUS -CreatePayloadToPatchResource ( - IN REDFISH_SERVICE *Service, - IN REDFISH_PAYLOAD *TargetPayload, - IN CHAR8 *Json, - OUT CHAR8 **Etag +ApplyFeatureSettingsStringArrayType ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING ConfigureLang, + IN RedfishCS_char_Array *ArrayHead ); /** - Find Redfish Resource Config Protocol that supports given schema and version. + Apply property value to UEFI HII database in numeric array type (INT64). - @param[in] Schema Schema name. - @param[in] Major Schema version major number. - @param[in] Minor Schema version minor number. - @param[in] Errata Schema version errata number. + @param[in] Schema Property schema. + @param[in] Version Property schema version. + @param[in] ConfigureLang Configure language refers to this property. + @param[in] ArrayHead Head of array value. - @retval EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL * Pointer to protocol - @retval NULL No protocol found. + @retval EFI_SUCCESS New value is applied successfully. + @retval Others Errors occur. **/ -EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL * -GetRedfishResourceConfigProtocol ( - IN CHAR8 *Schema, - IN CHAR8 *Major, - IN CHAR8 *Minor, - IN CHAR8 *Errata +EFI_STATUS +ApplyFeatureSettingsNumericArrayType ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING ConfigureLang, + IN RedfishCS_int64_Array *ArrayHead ); /** - Get supported schema list by given specify schema name. + Apply property value to UEFI HII database in boolean array type (INT64). - @param[in] Schema Schema type name. - @param[out] SchemaInfo Returned schema information. + @param[in] Schema Property schema. + @param[in] Version Property schema version. + @param[in] ConfigureLang Configure language refers to this property. + @param[in] ArrayHead Head of Redfich CS boolean array value. - @retval EFI_SUCCESS Schema information is returned successfully. - @retval Others Errors occur. + @retval EFI_SUCCESS New value is applied successfully. + @retval Others Errors occur. **/ EFI_STATUS -GetSupportedSchemaVersion ( - IN CHAR8 *Schema, - OUT REDFISH_SCHEMA_INFO *SchemaInfo +ApplyFeatureSettingsBooleanArrayType ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING ConfigureLang, + IN RedfishCS_bool_Array *ArrayHead ); /** - Return system root path + Create HTTP payload and send them to redfish service with POST method. + + @param[in] Service Redfish service. + @param[in] TargetPayload Target payload + @param[in] Json Data in JSON format. + @param[out] Location Returned location string from Redfish service. + @param[out] Etag Returned ETAG string from Redfish service. - @retval NULL Can not find system root path. - @retval Other System root path is returned. + @retval EFI_SUCCESS Data is sent to redfish service successfully. + @retval Others Errors occur. **/ -CHAR8 * -RedfishGetSystemRootPath ( - VOID +EFI_STATUS +CreatePayloadToPostResource ( + IN REDFISH_SERVICE *Service, + IN REDFISH_PAYLOAD *TargetPayload, + IN CHAR8 *Json, + OUT EFI_STRING *Location, + OUT CHAR8 **Etag ); /** - Get schema information by given protocol and service instance. + Create HTTP payload and send them to redfish service with PATCH method. - @param[in] RedfishService Pointer to Redfish service instance. - @param[in] JsonStructProtocol Json Structure protocol instance. - @param[in] Uri Target URI. - @param[out] SchemaInfo Returned schema information. + @param[in] Service Redfish service. + @param[in] TargetPayload Target payload + @param[in] Json Data in JSON format. + @param[out] Etag Returned ETAG string from Redfish service. - @retval EFI_SUCCESS Schema information is returned successfully. - @retval Others Errors occur. + @retval EFI_SUCCESS Data is sent to redfish service successfully. + @retval Others Errors occur. **/ EFI_STATUS -GetRedfishSchemaInfo ( - IN REDFISH_SERVICE *RedfishService, - IN EFI_REST_JSON_STRUCTURE_PROTOCOL *JsonStructProtocol, - IN CHAR8 *Uri, - OUT REDFISH_SCHEMA_INFO *SchemaInfo +CreatePayloadToPatchResource ( + IN REDFISH_SERVICE *Service, + IN REDFISH_PAYLOAD *TargetPayload, + IN CHAR8 *Json, + OUT CHAR8 **Etag + ); + +/** + + Save Redfish URI in database for further use. + + @param[in] ConfigLang ConfigLang to save + @param[in] Uri Redfish Uri to save + + @retval EFI_INVALID_PARAMETR SystemId is NULL or EMPTY + @retval EFI_SUCCESS Redfish uri is saved + +**/ +EFI_STATUS +RedfisSetRedfishUri ( + IN EFI_STRING ConfigLang, + IN EFI_STRING Uri ); /** Get the property name by given Configure Langauge. - @param[in] ConfigureLang Configure Language string. + @param[in] ResourceUri URI of root of resource. + @param[in] ConfigureLang Configure Language string. @retval EFI_STRING Pointer to property name. @retval NULL There is error. @@ -335,6 +456,7 @@ GetRedfishSchemaInfo ( **/ EFI_STRING GetPropertyFromConfigureLang ( + IN EFI_STRING ResourceUri, IN EFI_STRING ConfigureLang ); @@ -417,25 +539,6 @@ PropertyChecker ( IN BOOLEAN ProvisionMode ); -/** - - Check and see if we need to do provisioning for this two properties. - - @param[in] PropertyBuffer1 Pointer to property instance 1. - @param[in] PropertyBuffer2 Pointer to property instance 2. - @param[in] ProvisionMode TRUE if we are in provision mode. FALSE otherwise. - - @retval TRUE Provision is required. - @retval FALSE Provision is not required. - -**/ -BOOLEAN -PropertyChecker2Parm ( - IN VOID *PropertyBuffer1, - IN VOID *PropertyBuffer2, - IN BOOLEAN ProvisionMode - ); - /** Keep ETAG string and URI string in database. @@ -450,7 +553,7 @@ PropertyChecker2Parm ( EFI_STATUS SetEtagWithUri ( IN CHAR8 *EtagStr, - IN CHAR8 *Uri + IN EFI_STRING Uri ); /** @@ -465,7 +568,396 @@ SetEtagWithUri ( **/ CHAR8 * GetEtagWithUri ( - IN CHAR8 *Uri + IN EFI_STRING Uri + ); + +/** + + Get @odata.id from give HTTP payload. It's call responsibility to release returned buffer. + + @param[in] Payload HTTP payload + + @retval NULL Can not find @odata.id from given payload. + @retval Others odata.id string is returned. + +**/ +EFI_STRING +GetOdataId ( + IN REDFISH_PAYLOAD *Payload + ); + +/** + + Return config language from given URI and prperty name. It's call responsibility to release returned buffer. + + @param[in] Uri The URI to match + @param[in] PropertyName The property name of resource. This is optional. + + @retval NULL Can not find redfish uri. + @retval Other redfish uri is returned. + +**/ +EFI_STRING +GetConfigureLang ( + IN CHAR8 *Uri, + IN CHAR8 *PropertyName OPTIONAL + ); + +/** + + Return redfish URI by given config language. It's call responsibility to release returned buffer. + + @param[in] ConfigLang ConfigLang to search. + + @retval NULL Can not find redfish uri. + @retval Other redfish uri is returned. + +**/ +EFI_STRING +RedfishGetUri ( + IN EFI_STRING ConfigLang + ); + +/** + + Return config language by given URI. It's call responsibility to release returned buffer. + + @param[in] Uri Uri to search. + + @retval NULL Can not find redfish uri. + @retval Other redfish uri is returned. + +**/ +EFI_STRING +RedfishGetConfigLanguage ( + IN EFI_STRING Uri + ); + +/** + + Convert Unicode string to ASCII string. It's call responsibility to release returned buffer. + + @param[in] UnicodeStr Unicode string to convert. + + @retval CHAR8 * ASCII string returned. + @retval NULL Errors occur. + +**/ +CHAR8 * +StrUnicodeToAscii ( + IN EFI_STRING UnicodeStr + ); + +/** + + Convert ASCII string to Unicode string. It's call responsibility to release returned buffer. + + @param[in] AsciiStr ASCII string to convert. + + @retval EFI_STRING Unicode string returned. + @retval NULL Errors occur. + +**/ +EFI_STRING +StrAsciiToUnicode ( + IN CHAR8 *AsciiStr + ); + +/** + + Check and see if ETAG is identical to what we keep in system. + + @param[in] Uri URI requested + @param[in] EtagInHeader ETAG string returned from HTTP request. + @param[in] EtagInJson ETAG string in JSON body. + + @retval TRUE ETAG is identical. + @retval FALSE ETAG is changed. + +**/ +BOOLEAN +CheckEtag ( + IN EFI_STRING Uri, + IN CHAR8 *EtagInHeader, + IN CHAR8 *EtagInJson + ); + +/** + + Get the property string value in array type. + + @param[in] Schema Schema of this property. + @param[in] Version Schema version. + @param[in] PropertyName Property name. + @param[in] ConfigureLang Configure Language of this property. + @param[out] ArraySize The size of returned array. + + @retval CHAR8 ** Returned string array. NULL while error happens. + +**/ +CHAR8 ** +GetPropertyStringArrayValue ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING PropertyName, + IN EFI_STRING ConfigureLang, + OUT UINTN *ArraySize + ); + +/** + + Get the property numeric value in array type. + + @param[in] Schema Schema of this property. + @param[in] Version Schema version. + @param[in] PropertyName Property name. + @param[in] ConfigureLang Configure Language of this property. + @param[out] ArraySize The size of returned array. + + @retval INT64 ** Returned integer array. NULL while error happens. + +**/ +INT64 * +GetPropertyNumericArrayValue ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING PropertyName, + IN EFI_STRING ConfigureLang, + OUT UINTN *ArraySize + ); + +/** + + Get the property boolean value in array type. + + @param[in] Schema Schema of this property. + @param[in] Version Schema version. + @param[in] PropertyName Property name. + @param[in] ConfigureLang Configure Language of this property. + @param[out] ArraySize The size of returned array. + + @retval BOOLEAN * Returned boolean array. NULL while error happens. + +**/ +BOOLEAN * +GetPropertyBooleanArrayValue ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING PropertyName, + IN EFI_STRING ConfigureLang, + OUT UINTN *ArraySize + ); + +/** + + Get the property value in the vague type. + + @param[in] Schema Schema of this property. + @param[in] Version Schema version. + @param[in] PropertyName Property name. + @param[in] ConfigureLang Configure Language of this property. + @param[out] NumberOfValues Return the number of vague type of values + + @retval RedfishCS_EmptyProp_KeyValue The pointer to the structure + of vague type of values. + +**/ +RedfishCS_EmptyProp_KeyValue * +GetPropertyVagueValue ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING PropertyName, + IN EFI_STRING ConfigureLang, + OUT UINT32 *NumberOfValues + ); + +/** + + Free the list of empty property key values. + + @param[in] EmptyPropKeyValueListHead The head of RedfishCS_EmptyProp_KeyValue + +**/ +VOID +FreeEmptyPropKeyValueList ( + RedfishCS_EmptyProp_KeyValue *EmptyPropKeyValueListHead + ); + +/** + + Check and see if given property is in JSON context or not + + @param[in] Property Property name string + @param[in] Json The JSON context to search. + + @retval TRUE Property is found in JSON context + @retval FALSE Property is not in JSON context + +**/ +BOOLEAN +MatchPropertyWithJsonContext ( + IN EFI_STRING Property, + IN CHAR8 *Json +); + +/** + + Create string array and append to arry node in Redfish JSON convert format. + + @param[in,out] Head The head of string array. + @param[in] StringArray Input string array. + @param[in] ArraySize The size of StringArray. + + @retval EFI_SUCCESS String array is created successfully. + @retval Others Error happens + +**/ +EFI_STATUS +AddRedfishCharArray ( + IN OUT RedfishCS_char_Array **Head, + IN CHAR8 **StringArray, + IN UINTN ArraySize + ); + +/** + + Create numeric array and append to arry node in Redfish JSON convert format. + + @param[in,out] Head The head of string array. + @param[in] NumericArray Input numeric array. + @param[in] ArraySize The size of StringArray. + + @retval EFI_SUCCESS String array is created successfully. + @retval Others Error happens + +**/ +EFI_STATUS +AddRedfishNumericArray ( + IN OUT RedfishCS_int64_Array **Head, + IN INT64 *NumericArray, + IN UINTN ArraySize + ); + +/** + + Create boolean array and append to arry node in Redfish JSON convert format. + + @param[in,out] Head The head of string array. + @param[in] BooleanArray Input boolean array. + @param[in] ArraySize The size of BooleanArray. + + @retval EFI_SUCCESS String array is created successfully. + @retval Others Error happens + +**/ +EFI_STATUS +AddRedfishBooleanArray ( + IN OUT RedfishCS_bool_Array **Head, + IN BOOLEAN *BooleanArray, + IN UINTN ArraySize + ); +/** + + Check and see if value in Redfish string array are all the same as the one + from HII configuration. + + @param[in] Head The head of string array. + @param[in] StringArray Input string array. + @param[in] ArraySize The size of StringArray. + + @retval TRUE All string in Redfish array are as same as string + in HII configuration array. + FALSE These two array are not identical. + +**/ +BOOLEAN +CompareRedfishStringArrayValues ( + IN RedfishCS_char_Array *Head, + IN CHAR8 **StringArray, + IN UINTN ArraySize + ); + +/** + + Check and see if value in Redfish numeric array are all the same as the one + from HII configuration. + + @param[in] Head The head of Redfish CS numeraic array. + @param[in] NumericArray Input numeric array. + @param[in] ArraySize The size of NumericArray. + + @retval TRUE All string in Redfish array are as same as integer + in HII configuration array. + FALSE These two array are not identical. + +**/ +BOOLEAN +CompareRedfishNumericArrayValues ( + IN RedfishCS_int64_Array *Head, + IN INT64 *NumericArray, + IN UINTN ArraySize + ); + +/** + + Check and see if value in Redfish boolean array are all the same as the one + from HII configuration. + + @param[in] Head The head of Redfish CS boolean array. + @param[in] BooleanArray Input boolean array. + @param[in] ArraySize The size of BooleanArray. + + @retval TRUE All string in Redfish array are as same as integer + in HII configuration array. + FALSE These two array are not identical. + +**/ +BOOLEAN +CompareRedfishBooleanArrayValues ( + IN RedfishCS_bool_Array *Head, + IN BOOLEAN *BooleanArray, + IN UINTN ArraySize + ); + +/** + + Check and see if any difference between two vague value set. + This is just a simple check. + + @param[in] RedfishVagueKeyValuePtr The vague key value sets on Redfish service. + @param[in] RedfishVagueKeyValueNumber The numebr of vague key value sets + @param[in] ConfigVagueKeyValuePtr The vague configuration on platform. + @param[in] ConfigVagueKeyValueNumber The numebr of vague key value sets + + @retval TRUE All values are the same. + FALSE There is some difference. + +**/ +BOOLEAN +CompareRedfishPropertyVagueValues ( + IN RedfishCS_EmptyProp_KeyValue *RedfishVagueKeyValuePtr, + IN UINT32 RedfishVagueKeyValueNumber, + IN RedfishCS_EmptyProp_KeyValue *ConfigVagueKeyValuePtr, + IN UINT32 ConfigVagueKeyValueNumber + ); + +/** + + Find "ETag" and "Location" from either HTTP header or Redfish response. + + @param[in] Response HTTP response + @param[out] Etag String buffer to return ETag + @param[out] Location String buffer to return Location + + @retval EFI_SUCCESS Data is found and returned. + @retval Others Errors occur. + +**/ +EFI_STATUS +GetEtagAndLocation ( + IN REDFISH_RESPONSE *Response, + OUT CHAR8 **Etag, OPTIONAL + OUT EFI_STRING *Location OPTIONAL ); #endif diff --git a/RedfishClientPkg/Include/RedfishJsonStructure/RedfishCsCommon.h b/RedfishClientPkg/Include/RedfishJsonStructure/RedfishCsCommon.h new file mode 100644 index 0000000000..4d0ae50fc8 --- /dev/null +++ b/RedfishClientPkg/Include/RedfishJsonStructure/RedfishCsCommon.h @@ -0,0 +1,14 @@ +/** @file + Wrapper file for RedfishCsCommon.h + + (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef WRAPPER_REDFISH_CS_COMMON_H_ +#define WRAPPER_REDFISH_CS_COMMON_H_ + +#include "ConverterLib/include/RedfishCsCommon.h" + +#endif diff --git a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityInternal.h b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityInternal.h index 7d38d327ef..38d2af52b2 100644 --- a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityInternal.h +++ b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityInternal.h @@ -1,7 +1,7 @@ /** @file Common header file for RedfishFeatureUtilityLib driver. - (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP
+ (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -11,33 +11,39 @@ #define REDFISH_FEATURE_INTERNAL_H_ #include +#include + +#include #include #include #include #include #include -#include -#include #include #include #include #include #include #include +#include +#include #include #include +#include #define INDEX_VARIABLE_SIZE 64 #define INDEX_STRING_SIZE 16 -#define IS_EMPTY_STRING(a) (a == NULL || a[0] == '\0') #define INDEX_STRING L"{%d}" #define SCHEMA_NAME_PREFIX "x-uefi-redfish-" #define SCHEMA_NAME_PREFIX_OFFSET (AsciiStrLen (SCHEMA_NAME_PREFIX)) -#define REDFISH_SYSTEM_ROOT_PATH "/v1/Systems[UUID~%g]" +#define REDFISH_ROOT_PATH "/v1" +#define REDFISH_ROOT_PATH_UNICODE L"/v1" #define MAX_CONF_LANG_LEN 128 +#define MAX_REDFISH_URL_LEN 255 +#define REGULAR_EXPRESSION_ARRAY L"\\[.*\\]/.*" #define BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE L"{" #define BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_END_SIGNATURE L"}" diff --git a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.c b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.c index cf8696e5f0..2bd7f58f9c 100644 --- a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.c +++ b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.c @@ -1,7 +1,7 @@ /** @file Redfish feature utility library implementation - (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP
+ (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -9,7 +9,34 @@ #include "RedfishFeatureUtilityInternal.h" -EDKII_REDFISH_ETAG_PROTOCOL *mEtagProtocol; +EDKII_REDFISH_ETAG_PROTOCOL *mEtagProtocol = NULL; +EDKII_REDFISH_CONFIG_LANG_MAP_PROTOCOL *mConfigLangMapProtocol = NULL; + + +EFI_STATUS +RedfishLocateProtocol ( + IN VOID **ProtocolInstance, + IN EFI_GUID *ProtocolGuid + ) +{ + EFI_STATUS Status; + + if (ProtocolInstance == NULL || ProtocolGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (*ProtocolInstance != NULL) { + return EFI_SUCCESS; + } + + Status = gBS->LocateProtocol ( + ProtocolGuid, + NULL, + ProtocolInstance + ); + return Status; +} + /** @@ -71,227 +98,168 @@ GetArraykeyFromUri ( /** - Keep configure language with given key in UEFI variable. + Keep ETAG string and URI string in database. - @param[in] Schema Schema name. - @param[in] Version Schema version. - @param[in] Key Key string. - @param[in] ConfigureLangIndex Index value. + @param[in] EtagStr ETAG string. + @param[in] Uri URI string. - @retval EFI_SUCCESS Data is saved in UEFI variable. - @retval Others Errors occur. + @retval EFI_SUCCESS ETAG and URI are applied successfully. + @retval Others Errors occur. **/ EFI_STATUS -SetConfigureLangWithkey ( - IN CHAR8 *Schema, - IN CHAR8 *Version, - IN CHAR8 *Key, - IN UINTN ConfigureLangIndex +SetEtagWithUri ( + IN CHAR8 *EtagStr, + IN EFI_STRING Uri ) { - CHAR16 IndexString[INDEX_STRING_SIZE]; - CHAR16 VarName[INDEX_VARIABLE_SIZE]; - CHAR16 *VarData; - EFI_STATUS Status; - // - // Variable content. - // - UnicodeSPrint (IndexString, sizeof (IndexString), INDEX_STRING, ConfigureLangIndex); + EFI_STATUS Status; + CHAR8 *AsciiUri; - // - // Variable name. - // - UnicodeSPrint (VarName, sizeof (VarName), L"%a_%a_%a", Schema, Version, Key); + if (IS_EMPTY_STRING (EtagStr) || IS_EMPTY_STRING (Uri)) { + return EFI_INVALID_PARAMETER; + } - // - // Check if it exists already. - // - Status = GetVariable2 ( - VarName, - &gEfiCallerIdGuid, - (VOID *)&VarData, - NULL - ); - if (!EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "%a, remove stale data: %s\n", __FUNCTION__, VarData)); - FreePool (VarData); - gRT->SetVariable (VarName, &gEfiCallerIdGuid, VARIABLE_ATTRIBUTE_NV_BS, 0, NULL); + Status = RedfishLocateProtocol ((VOID **)&mEtagProtocol, &gEdkIIRedfishETagProtocolGuid); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, fail to locate gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status)); + return Status; } - return gRT->SetVariable (VarName, &gEfiCallerIdGuid, VARIABLE_ATTRIBUTE_NV_BS, StrSize (IndexString), (VOID *)&IndexString); + AsciiUri = StrUnicodeToAscii (Uri); + if (AsciiUri == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + mEtagProtocol->Set (mEtagProtocol, AsciiUri, EtagStr); + mEtagProtocol->Flush (mEtagProtocol); + + FreePool (AsciiUri); + + return EFI_SUCCESS; } /** - Find configure language with input key string. + Find ETAG string that refers to given URI. - @param[in] Schema Schema name. - @param[in] Version Schema version. - @param[in] Property Property name. - @param[in] Key Key string. + @param[in] Uri Target URI string. - @retval CHAR16 * Corresponding configure langauge - @retval NULL No configure language is found + @retval CHAR8 * ETAG string + @retval NULL No ETAG is found. **/ -CHAR16 * -GetConfigureLangByKey ( - IN CHAR8 *Schema, - IN CHAR8 *Version, - IN CHAR8 *Property, OPTIONAL - IN CHAR8 *Key +CHAR8 * +GetEtagWithUri ( + IN EFI_STRING Uri ) { - EFI_STATUS Status; - CHAR16 VariableName[64]; - UINTN VariableSize; - CHAR16 *CollectionIndex; - CHAR16 *ConfigureLang; - UINTN ConfigureLangLen; + EFI_STATUS Status; + CHAR8 *AsciiUri; + CHAR8 *EtagStr; - if (Schema == NULL || Version == NULL || Key == NULL) { + if (IS_EMPTY_STRING (Uri)) { return NULL; } - CollectionIndex = NULL; - ConfigureLang = NULL; - - UnicodeSPrint (VariableName, 64, L"%a_%a_%a", Schema, Version, Key); - - Status = GetVariable2 ( - VariableName, - &gEfiCallerIdGuid, - (VOID *)&CollectionIndex, - &VariableSize - ); + Status = RedfishLocateProtocol ((VOID **)&mEtagProtocol, &gEdkIIRedfishETagProtocolGuid); if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, fail to locate gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status)); return NULL; } - ConfigureLangLen = AsciiStrLen (Schema) + StrLen (CollectionIndex) + (Property == NULL ? 0 : AsciiStrLen (Property)) + 3 + 1; - ConfigureLang = AllocatePool (sizeof (CHAR16) * ConfigureLangLen); - ASSERT (ConfigureLang); - - if (Property != NULL) { - UnicodeSPrint (ConfigureLang, sizeof (CHAR16) * ConfigureLangLen, L"/%a/%s/%a", Schema, CollectionIndex, Property); - } else { - UnicodeSPrint (ConfigureLang, sizeof (CHAR16) * ConfigureLangLen, L"/%a/%s", Schema, CollectionIndex); + AsciiUri = StrUnicodeToAscii (Uri); + if (AsciiUri == NULL) { + return NULL; } - FreePool (CollectionIndex); - - return ConfigureLang; -} - -/** - - Keep ETAG string and URI string in database. - - @param[in] EtagStr ETAG string. - @param[in] Uri URI string. - - @retval EFI_SUCCESS ETAG and URI are applied successfully. - @retval Others Errors occur. - -**/ -EFI_STATUS -SetEtagWithUri ( - IN CHAR8 *EtagStr, - IN CHAR8 *Uri - ) -{ - EFI_STATUS Status; + Status = mEtagProtocol->Get (mEtagProtocol, AsciiUri, &EtagStr); - if (IS_EMPTY_STRING (EtagStr) || IS_EMPTY_STRING (Uri)) { - return EFI_INVALID_PARAMETER; - } + FreePool (AsciiUri); - if (mEtagProtocol == NULL) { - Status = gBS->LocateProtocol ( - &gEdkIIRedfishETagProtocolGuid, - NULL, - (VOID **)&mEtagProtocol - ); - if (EFI_ERROR (Status)) { - return Status; - } + if (EFI_ERROR (Status)) { + return NULL; } - mEtagProtocol->Set (mEtagProtocol, Uri, EtagStr); - mEtagProtocol->Flush (mEtagProtocol); - - return EFI_SUCCESS; + return EtagStr; } /** - Find ETAG string that refers to given URI. + Convert Unicode string to ASCII string. It's call responsibility to release returned buffer. - @param[in] Uri Target URI string. + @param[in] UnicodeStr Unicode string to convert. - @retval CHAR8 * ETAG string - @retval NULL No ETAG is found. + @retval CHAR8 * ASCII string returned. + @retval NULL Errors occur. **/ CHAR8 * -GetEtagWithUri ( - IN CHAR8 *Uri +StrUnicodeToAscii ( + IN EFI_STRING UnicodeStr ) { - EFI_STATUS Status; - CHAR8 *EtagStr; + CHAR8 *AsciiStr; + UINTN AsciiStrSize; + EFI_STATUS Status; - if (IS_EMPTY_STRING (Uri)) { + if (IS_EMPTY_STRING (UnicodeStr)) { return NULL; } - if (mEtagProtocol == NULL) { - Status = gBS->LocateProtocol ( - &gEdkIIRedfishETagProtocolGuid, - NULL, - (VOID **)&mEtagProtocol - ); - if (EFI_ERROR (Status)) { - return NULL; - } + AsciiStrSize = StrLen (UnicodeStr) + 1; + AsciiStr = AllocatePool (AsciiStrSize); + if (AsciiStr == NULL) { + return NULL; } - Status = mEtagProtocol->Get (mEtagProtocol, Uri, &EtagStr); + Status = UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSize); if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status)); + FreePool (AsciiStr); return NULL; } - return EtagStr; + return AsciiStr; } /** - Convert HII string value to string value in JSON format. + Convert ASCII string to Unicode string. It's call responsibility to release returned buffer. - @param[in] HiiStringValue String in HII format. + @param[in] AsciiStr ASCII string to convert. - @retval CHAR8 * String in JSON format. + @retval EFI_STRING Unicode string returned. @retval NULL Errors occur. **/ -CHAR8 * -ConvertHiiStringValueToJsonStringValue ( - IN EFI_STRING HiiStringValue +EFI_STRING +StrAsciiToUnicode ( + IN CHAR8 *AsciiStr ) { - CHAR8 *JsonValue; - UINTN JsonValueSize; + EFI_STRING UnicodeStr; + UINTN UnicodeStrSize; + EFI_STATUS Status; - if (IS_EMPTY_STRING (HiiStringValue)) { + if (IS_EMPTY_STRING (AsciiStr)) { return NULL; } - JsonValueSize = StrLen (HiiStringValue) + 1; - JsonValue = AllocatePool (JsonValueSize); - UnicodeStrToAsciiStrS (HiiStringValue, JsonValue, JsonValueSize); + UnicodeStrSize = (AsciiStrLen (AsciiStr) + 1) * sizeof (CHAR16); + UnicodeStr = AllocatePool (UnicodeStrSize); + if (UnicodeStr == NULL) { + return NULL; + } + + Status = AsciiStrToUnicodeStrS (AsciiStr, UnicodeStr, UnicodeStrSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "t failed: %r\n", Status)); + FreePool (UnicodeStr); + return NULL; + } - return JsonValue; + return UnicodeStr; } /** @@ -480,997 +448,2979 @@ ApplyFeatureSettingsBooleanType ( /** - Read redfish resource by given resource path. + Apply property value to UEFI HII database in vague type. - @param[in] Service Redfish srvice instacne to make query. - @param[in] ResourcePath Target resource path. - @param[out] Response HTTP response from redfish service. + @param[in] Schema Property schema. + @param[in] Version Property schema version. + @param[in] ConfigureLang Configure language refers to this property. + @param[in] VagueValuePtr Pointer of vague values to to set. + @param[in] NumVagueValues Number of vague values. - @retval EFI_SUCCESS Resrouce is returned successfully. + @retval EFI_SUCCESS New value is applied successfully. @retval Others Errors occur. **/ EFI_STATUS -GetResourceByPath ( - IN REDFISH_SERVICE *Service, - IN CHAR8 *ResourcePath, - OUT REDFISH_RESPONSE *Response +ApplyFeatureSettingsVagueType ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING ConfigureLang, + IN RedfishCS_EmptyProp_KeyValue *VagueValuePtr, + IN UINT32 NumberOfVagueValues ) { - EFI_STATUS Status; - - if (Service == NULL || Response == NULL || IS_EMPTY_STRING (ResourcePath)) { + EFI_STATUS Status; + UINTN StrSize; + CHAR8 *ConfigureLangAscii; + CHAR8 *ConfigureLangKeyAscii; + EFI_STRING ConfigureKeyLang; + EDKII_REDFISH_VALUE RedfishValue; + EDKII_REDFISH_VALUE_TYPES PropertyDatatype; + RedfishCS_EmptyProp_KeyValue *CurrentVagueValuePtr; + + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || VagueValuePtr == NULL || NumberOfVagueValues == 0) { return EFI_INVALID_PARAMETER; } - // - // Get resource from redfish service. - // - Status = RedfishGetByService ( - Service, - ResourcePath, - Response - ); + ConfigureLangAscii = AllocatePool (StrLen (ConfigureLang) + 1); + if (ConfigureLangAscii == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_ERROR, "%a, Allocate memory for generate ConfigureLang of vague key of %a.%a %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLang, Status)); + return Status; + } + Status = UnicodeStrToAsciiStrS (ConfigureLang, ConfigureLangAscii, StrLen (ConfigureLang) + 1); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a, RedfishGetByService to %a failed: %r\n", __FUNCTION__, ResourcePath, Status)); - if (Response->Payload != NULL) { - RedfishDumpPayload (Response->Payload); - RedfishFreeResponse ( - NULL, - 0, - NULL, - Response->Payload - ); - Response->Payload = NULL; - } - + DEBUG ((DEBUG_ERROR, "%a, Convert the configureLang of vague key of %a.%a %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLang, Status)); return Status; } + CurrentVagueValuePtr = VagueValuePtr; + while (CurrentVagueValuePtr != NULL) { + // + // Generate ConfigureLang with the key name + // + //ConfigureKeyLang = GetConfigureLang (ConfigureLangAscii, CurrentVagueValuePtr->KeyNamePtr); + StrSize = AsciiStrLen (ConfigureLangAscii) + AsciiStrLen (CurrentVagueValuePtr->KeyNamePtr) + 2; + ConfigureLangKeyAscii = AllocateZeroPool (StrSize); + ConfigureKeyLang = AllocateZeroPool (StrSize * sizeof (CHAR16)); + if (ConfigureLangKeyAscii == NULL || ConfigureKeyLang == NULL) { + DEBUG ((DEBUG_ERROR, "%a, Generate ConfigureLang of vague key of %a.%a %s %a failed!\n", __FUNCTION__, Schema, Version, ConfigureLang, CurrentVagueValuePtr->KeyNamePtr)); + goto ErrorContinue; + } + AsciiStrCatS(ConfigureLangKeyAscii, StrSize, ConfigureLangAscii); + AsciiStrCatS(ConfigureLangKeyAscii, StrSize, "/"); + AsciiStrCatS(ConfigureLangKeyAscii, StrSize, CurrentVagueValuePtr->KeyNamePtr); + AsciiStrToUnicodeStrS(ConfigureLangKeyAscii, ConfigureKeyLang, StrSize); + FreePool (ConfigureLangKeyAscii); + ConfigureLangKeyAscii = NULL; + // + // Initial property data type and value. + // + if (CurrentVagueValuePtr->Value->DataType == RedfishCS_Vague_DataType_String) { + PropertyDatatype = REDFISH_VALUE_TYPE_STRING; + } else if (CurrentVagueValuePtr->Value->DataType == RedfishCS_Vague_DataType_Bool) { + PropertyDatatype = REDFISH_VALUE_TYPE_BOOLEAN; + } else if (CurrentVagueValuePtr->Value->DataType == RedfishCS_Vague_DataType_Int64) { + PropertyDatatype = REDFISH_VALUE_TYPE_INTEGER; + } else { + DEBUG((DEBUG_ERROR, "%a, %a.%a %s Unsupported Redfish property data type\n", __FUNCTION__, Schema, Version, ConfigureLang)); + goto ErrorContinue; + } + + // + // Get the current value from HII + // + Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureKeyLang, &RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureKeyLang, Status)); + } else { + if (RedfishValue.Type != PropertyDatatype) { + DEBUG((DEBUG_ERROR, "%a, %a.%a %s mismatched data type\n", __FUNCTION__, Schema, Version, ConfigureKeyLang)); + goto ErrorContinue; + } + if (PropertyDatatype == REDFISH_VALUE_TYPE_STRING) { + // + // This is a string property. + // + if (AsciiStrCmp (CurrentVagueValuePtr->Value->DataValue.CharPtr, RedfishValue.Value.Buffer) != 0) { + // + // Apply settings from redfish + // + DEBUG ((DEBUG_INFO, "%a, %a.%a apply %s from %a to %a\n", __FUNCTION__, Schema, Version, ConfigureKeyLang, RedfishValue.Value.Buffer, CurrentVagueValuePtr->Value->DataValue.CharPtr)); + FreePool (RedfishValue.Value.Buffer); + RedfishValue.Value.Buffer = CurrentVagueValuePtr->Value->DataValue.CharPtr; + Status = RedfishPlatformConfigSetValue (Schema, Version, ConfigureKeyLang, RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, apply %a to %a failed: %r\n", __FUNCTION__, ConfigureKeyLang, CurrentVagueValuePtr->Value->DataValue.CharPtr, Status)); + } + } else { + DEBUG ((DEBUG_INFO, "%a, %a.%a %s value is: %a\n", __FUNCTION__, Schema, Version, ConfigureKeyLang, RedfishValue.Value.Buffer, Status)); + } + } else if (PropertyDatatype == REDFISH_VALUE_TYPE_BOOLEAN) { + // + // This is a boolean property. + // + if (RedfishValue.Value.Boolean != *CurrentVagueValuePtr->Value->DataValue.BoolPtr) { + // + // Apply settings from redfish + // + DEBUG ((DEBUG_INFO, "%a, %a.%a apply %s from %a to %a\n", + __FUNCTION__, + Schema, + Version, + ConfigureKeyLang, + (RedfishValue.Value.Boolean ? "True" : "False"), + (*CurrentVagueValuePtr->Value->DataValue.BoolPtr ? "True" : "False"))); + + RedfishValue.Value.Boolean = (BOOLEAN)*CurrentVagueValuePtr->Value->DataValue.BoolPtr; + Status = RedfishPlatformConfigSetValue (Schema, Version, ConfigureKeyLang, RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, apply %s to %a failed: %r\n", __FUNCTION__, ConfigureKeyLang, (*CurrentVagueValuePtr->Value->DataValue.BoolPtr ? "True" : "False"), Status)); + } + } else { + DEBUG ((DEBUG_INFO, "%a, %a.%a %s value is: %a\n", __FUNCTION__, Schema, Version, ConfigureKeyLang, (RedfishValue.Value.Boolean ? "True" : "False"), Status)); + } + } else if (PropertyDatatype == REDFISH_VALUE_TYPE_INTEGER) { + // + // This is a integer property. + // + if (RedfishValue.Value.Integer != *CurrentVagueValuePtr->Value->DataValue.Int64Ptr) { + // + // Apply settings from redfish + // + DEBUG ((DEBUG_INFO, "%a, %a.%a apply %s from 0x%x to 0x%x\n", __FUNCTION__, Schema, Version, ConfigureKeyLang, RedfishValue.Value.Integer, *CurrentVagueValuePtr->Value->DataValue.Int64Ptr)); + + RedfishValue.Value.Integer = (INT64)*CurrentVagueValuePtr->Value->DataValue.Int64Ptr; + Status = RedfishPlatformConfigSetValue (Schema, Version, ConfigureKeyLang, RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, apply %s to 0x%x failed: %r\n", __FUNCTION__, ConfigureKeyLang, *CurrentVagueValuePtr->Value->DataValue.Int64Ptr, Status)); + } + } else { + DEBUG ((DEBUG_INFO, "%a, %a.%a %s value is: 0x%x\n", __FUNCTION__, Schema, Version, ConfigureKeyLang, RedfishValue.Value.Integer, Status)); + } + } else { + DEBUG((DEBUG_ERROR, "%a, %a.%a %s Unsupported Redfish property data type\n", __FUNCTION__, Schema, Version, ConfigureLang)); + goto ErrorContinue; + } + } + +ErrorContinue:; + if (ConfigureLangKeyAscii != NULL) { + FreePool (ConfigureLangKeyAscii); + ConfigureLangKeyAscii = NULL; + } + if (ConfigureKeyLang != NULL) { + FreePool (ConfigureKeyLang); + ConfigureKeyLang = NULL; + } + CurrentVagueValuePtr = CurrentVagueValuePtr->NextKeyValuePtr; + }; + + if (ConfigureLangAscii != NULL) { + FreePool (ConfigureLangAscii); + } + if (ConfigureLangKeyAscii != NULL) { + FreePool (ConfigureLangKeyAscii); + } + if (ConfigureKeyLang != NULL) { + FreePool (ConfigureKeyLang); + } return EFI_SUCCESS; } /** - Find array index from given configure language string. - - @param[in] ConfigureLang Configure language string to parse. - @param[out] UnifiedConfigureLang The configure language in array. - @param[out] Index The array index number. + Release the memory in RedfishValue while value type is array. - @retval EFI_SUCCESS Index is found. - @retval Others Errors occur. + @param[in] RedfishValue Pointer to Redfish value **/ -EFI_STATUS -GetArrayIndexFromArrayTypeConfigureLang ( - IN CHAR16 *ConfigureLang, - OUT CHAR16 **UnifiedConfigureLang, - OUT UINTN *Index +VOID +FreeArrayTypeRedfishValue ( + EDKII_REDFISH_VALUE *RedfishValue ) { - CHAR16 *TmpConfigureLang; - CHAR16 *IndexString; - CHAR16 *TmpString; - - if (ConfigureLang == NULL || UnifiedConfigureLang == NULL || Index == NULL) { - return EFI_INVALID_PARAMETER; - } - - TmpConfigureLang = AllocateCopyPool (StrSize (ConfigureLang), ConfigureLang); - if (TmpConfigureLang == NULL) { - return EFI_OUT_OF_RESOURCES; - } + UINTN Index; - // - // looking for index signature "{"" - // - IndexString = StrStr (TmpConfigureLang, BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE); - if (IndexString == NULL) { - return EFI_NOT_FOUND; + if (RedfishValue == NULL) { + return; } - // - // Skip "{" - // - TmpString = IndexString + StrLen (BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE); - - // - // Looking for "}" - // - TmpString = StrStr (TmpString, BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_END_SIGNATURE); - if (TmpString == NULL) { - return EFI_NOT_FOUND; + if (RedfishValue->Type != REDFISH_VALUE_TYPE_INTEGER_ARRAY && RedfishValue->Type != REDFISH_VALUE_TYPE_STRING_ARRAY) { + return; } - // - // Append '\0' for converting decimal string to integer. - // - TmpString[0] = '\0'; + switch (RedfishValue->Type) { + case REDFISH_VALUE_TYPE_STRING_ARRAY: + for (Index = 0; Index < RedfishValue->ArrayCount; Index++) { + FreePool (RedfishValue->Value.StringArray[Index]); + } + FreePool (RedfishValue->Value.StringArray); + RedfishValue->Value.StringArray = NULL; + break; - // - // Convert decimal string to integer - // - *Index = StrDecimalToUintn (IndexString + StrLen (BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE)); + case REDFISH_VALUE_TYPE_INTEGER_ARRAY: + FreePool (RedfishValue->Value.IntegerArray); + RedfishValue->Value.IntegerArray = NULL; + break; - // - // Resotre the '}' character and remove rest of string. - // - TmpString[0] = L'}'; - TmpString[1] = '\0'; + case REDFISH_VALUE_TYPE_BOOLEAN_ARRAY: + FreePool (RedfishValue->Value.BooleanArray); + RedfishValue->Value.BooleanArray = NULL; + break; - *UnifiedConfigureLang = TmpConfigureLang; + default: + return; + } - return EFI_SUCCESS; + RedfishValue->ArrayCount = 0; } + /** - Search HII database with given Configure Language pattern. Data is handled and - returned in array. + Apply property value to UEFI HII database in string array type. - @param[in] Schema The schema to search. - @param[in] Version The schema version. - @param[in] Pattern Configure Language pattern to search. - @param[out] UnifiedConfigureLangList The data returned by HII database. + @param[in] Schema Property schema. + @param[in] Version Property schema version. + @param[in] ConfigureLang Configure language refers to this property. + @param[in] ArrayHead Head of array value. - @retval EFI_SUCCESS Data is found and returned. + @retval EFI_SUCCESS New value is applied successfully. @retval Others Errors occur. **/ EFI_STATUS -RedfishFeatureGetUnifiedArrayTypeConfigureLang ( - IN CHAR8 *Schema, - IN CHAR8 *Version, - IN EFI_STRING Pattern, OPTIONAL - OUT REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST *UnifiedConfigureLangList +ApplyFeatureSettingsStringArrayType ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING ConfigureLang, + IN RedfishCS_char_Array *ArrayHead ) { - EFI_STATUS Status; - EFI_STRING *ConfigureLangList; - UINTN Count; - UINTN Index; - UINTN Index2; - UINTN ArrayIndex; - EFI_STRING UnifiedConfigureLang; - BOOLEAN Duplicated; - REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG UnifiedConfigureLangPool[BIOS_CONFIG_TO_REDFISH_REDPATH_POOL_SIZE]; + EFI_STATUS Status; + EDKII_REDFISH_VALUE RedfishValue; + UINTN Index; + RedfishCS_char_Array *Buffer; - if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || UnifiedConfigureLangList == NULL) { + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || ArrayHead == NULL) { return EFI_INVALID_PARAMETER; } - UnifiedConfigureLangList->Count = 0; - UnifiedConfigureLangList->List = NULL; - ZeroMem (UnifiedConfigureLangPool, sizeof (UnifiedConfigureLangPool)); - - Status = RedfishPlatformConfigGetConfigureLang (Schema, Version, Pattern, &ConfigureLangList, &Count); + // + // Get the current value from HII + // + Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLang, &RedfishValue); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a, RedfishFeatureGetConfigureLangRegex failed: %r\n", __FUNCTION__, Status)); - return Status; - } + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLang, Status)); + } else { - if (Count == 0) { - return EFI_NOT_FOUND; + if (RedfishValue.Type != REDFISH_VALUE_TYPE_STRING_ARRAY) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string array type\n", __FUNCTION__, Schema, Version, ConfigureLang)); + return EFI_DEVICE_ERROR; + } + + // + // If there is no change in array, do nothing + // + if (!CompareRedfishStringArrayValues (ArrayHead, RedfishValue.Value.StringArray, RedfishValue.ArrayCount)) { + // + // Apply settings from redfish + // + DEBUG ((DEBUG_INFO, "%a, %a.%a apply %s for array\n", __FUNCTION__, Schema, Version, ConfigureLang)); + FreeArrayTypeRedfishValue (&RedfishValue); + + // + // Convert array from RedfishCS_char_Array to EDKII_REDFISH_VALUE + // + RedfishValue.ArrayCount = 0; + Buffer = ArrayHead; + while (Buffer != NULL) { + RedfishValue.ArrayCount += 1; + Buffer = Buffer->Next; + } + + // + // Allocate pool for new values + // + RedfishValue.Value.StringArray = AllocatePool (RedfishValue.ArrayCount *sizeof (CHAR8 *)); + if (RedfishValue.Value.StringArray == NULL) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + Buffer = ArrayHead; + Index = 0; + while (Buffer != NULL) { + RedfishValue.Value.StringArray[Index] = AllocateCopyPool (AsciiStrSize (Buffer->ArrayValue), Buffer->ArrayValue); + if (RedfishValue.Value.StringArray[Index] == NULL) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + Buffer = Buffer->Next; + Index++; + } + + ASSERT (Index <= RedfishValue.ArrayCount); + + Status = RedfishPlatformConfigSetValue (Schema, Version, ConfigureLang, RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, apply %s array failed: %r\n", __FUNCTION__, ConfigureLang, Status)); + } + } else { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s array value has no change\n", __FUNCTION__, Schema, Version, ConfigureLang)); + } } - for (Index = 0; Index < Count; Index++) { - Status = GetArrayIndexFromArrayTypeConfigureLang (ConfigureLangList[Index], &UnifiedConfigureLang, &ArrayIndex); - if (EFI_ERROR (Status)) { - ASSERT (FALSE); - continue; + return Status; +} + +/** + + Apply property value to UEFI HII database in numeric array type (INT64). + + @param[in] Schema Property schema. + @param[in] Version Property schema version. + @param[in] ConfigureLang Configure language refers to this property. + @param[in] ArrayHead Head of array value. + + @retval EFI_SUCCESS New value is applied successfully. + @retval Others Errors occur. + +**/ +EFI_STATUS +ApplyFeatureSettingsNumericArrayType ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING ConfigureLang, + IN RedfishCS_int64_Array *ArrayHead + ) +{ + EFI_STATUS Status; + EDKII_REDFISH_VALUE RedfishValue; + UINTN Index; + RedfishCS_int64_Array *Buffer; + + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || ArrayHead == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the current value from HII + // + Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLang, &RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLang, Status)); + } else { + + if (RedfishValue.Type != REDFISH_VALUE_TYPE_INTEGER_ARRAY) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string array type\n", __FUNCTION__, Schema, Version, ConfigureLang)); + return EFI_DEVICE_ERROR; } // - // Check if this configure language is duplicated. + // If there is no change in array, do nothing // - Duplicated = FALSE; - for (Index2 = 0; Index2 < BIOS_CONFIG_TO_REDFISH_REDPATH_POOL_SIZE; Index2++) { - if (UnifiedConfigureLangPool[Index2].ConfigureLang == NULL) { - break; + if (!CompareRedfishNumericArrayValues (ArrayHead, RedfishValue.Value.IntegerArray, RedfishValue.ArrayCount)) { + // + // Apply settings from redfish + // + DEBUG ((DEBUG_INFO, "%a, %a.%a apply %s for array\n", __FUNCTION__, Schema, Version, ConfigureLang)); + FreeArrayTypeRedfishValue (&RedfishValue); + + // + // Convert array from RedfishCS_int64_Array to EDKII_REDFISH_VALUE + // + RedfishValue.ArrayCount = 0; + Buffer = ArrayHead; + while (Buffer != NULL) { + RedfishValue.ArrayCount += 1; + Buffer = Buffer->Next; + } + + // + // Allocate pool for new values + // + RedfishValue.Value.IntegerArray = AllocatePool (RedfishValue.ArrayCount * sizeof (INT64)); + if (RedfishValue.Value.IntegerArray == NULL) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + Buffer = ArrayHead; + Index = 0; + while (Buffer != NULL) { + RedfishValue.Value.IntegerArray[Index] = (INT64)*Buffer->ArrayValue; + Buffer = Buffer->Next; + Index++; + } + + ASSERT (Index <= RedfishValue.ArrayCount); + + Status = RedfishPlatformConfigSetValue (Schema, Version, ConfigureLang, RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, apply %s array failed: %r\n", __FUNCTION__, ConfigureLang, Status)); + } + } else { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s array value has no change\n", __FUNCTION__, Schema, Version, ConfigureLang)); + } + } + + return Status; +} + +/** + + Apply property value to UEFI HII database in boolean array type (INT64). + + @param[in] Schema Property schema. + @param[in] Version Property schema version. + @param[in] ConfigureLang Configure language refers to this property. + @param[in] ArrayHead Head of Redfich CS boolean array value. + + @retval EFI_SUCCESS New value is applied successfully. + @retval Others Errors occur. + +**/ +EFI_STATUS +ApplyFeatureSettingsBooleanArrayType ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING ConfigureLang, + IN RedfishCS_bool_Array *ArrayHead + ) +{ + EFI_STATUS Status; + EDKII_REDFISH_VALUE RedfishValue; + UINTN Index; + RedfishCS_bool_Array *Buffer; + + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || ArrayHead == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the current value from HII + // + Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLang, &RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLang, Status)); + } else { + + if (RedfishValue.Type != REDFISH_VALUE_TYPE_BOOLEAN_ARRAY) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string array type\n", __FUNCTION__, Schema, Version, ConfigureLang)); + return EFI_DEVICE_ERROR; + } + + // + // If there is no change in array, do nothing + // + if (!CompareRedfishBooleanArrayValues (ArrayHead, RedfishValue.Value.BooleanArray, RedfishValue.ArrayCount)) { + // + // Apply settings from redfish + // + DEBUG ((DEBUG_INFO, "%a, %a.%a apply %s for array\n", __FUNCTION__, Schema, Version, ConfigureLang)); + FreeArrayTypeRedfishValue (&RedfishValue); + + // + // Convert array from RedfishCS_int64_Array to EDKII_REDFISH_VALUE + // + RedfishValue.ArrayCount = 0; + Buffer = ArrayHead; + while (Buffer != NULL) { + RedfishValue.ArrayCount += 1; + Buffer = Buffer->Next; + } + + // + // Allocate pool for new values + // + RedfishValue.Value.BooleanArray = AllocatePool (RedfishValue.ArrayCount * sizeof (BOOLEAN)); + if (RedfishValue.Value.BooleanArray == NULL) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + Buffer = ArrayHead; + Index = 0; + while (Buffer != NULL) { + RedfishValue.Value.BooleanArray[Index] = (BOOLEAN)*Buffer->ArrayValue; + Buffer = Buffer->Next; + Index++; + } + + ASSERT (Index <= RedfishValue.ArrayCount); + + Status = RedfishPlatformConfigSetValue (Schema, Version, ConfigureLang, RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, apply %s array failed: %r\n", __FUNCTION__, ConfigureLang, Status)); + } + } else { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s array value has no change\n", __FUNCTION__, Schema, Version, ConfigureLang)); + } + } + + return Status; +} + +/** + + Read redfish resource by given resource URI. + + @param[in] Service Redfish srvice instacne to make query. + @param[in] ResourceUri Target resource URI. + @param[out] Response HTTP response from redfish service. + + @retval EFI_SUCCESS Resrouce is returned successfully. + @retval Others Errors occur. + +**/ +EFI_STATUS +GetResourceByUri ( + IN REDFISH_SERVICE *Service, + IN EFI_STRING ResourceUri, + OUT REDFISH_RESPONSE *Response + ) +{ + EFI_STATUS Status; + CHAR8 *AsciiResourceUri; + + if (Service == NULL || Response == NULL || IS_EMPTY_STRING (ResourceUri)) { + return EFI_INVALID_PARAMETER; + } + + AsciiResourceUri = StrUnicodeToAscii (ResourceUri); + if (AsciiResourceUri == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get resource from redfish service. + // + Status = RedfishGetByUri ( + Service, + AsciiResourceUri, + Response + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, RedfishGetByUri to %a failed: %r\n", __FUNCTION__, AsciiResourceUri, Status)); + if (Response->Payload != NULL) { + RedfishDumpPayload (Response->Payload); + RedfishFreeResponse ( + NULL, + 0, + NULL, + Response->Payload + ); + Response->Payload = NULL; + } + } + + if (AsciiResourceUri != NULL) { + FreePool (AsciiResourceUri); + } + + return Status; +} + +/** + + Check if this is the Redpath array. Usually the Redpath array represents + the collection member. Return + + @param[in] ConfigureLang The Redpath to check + @param[out] ArraySignatureOpen String to the open of array signature. + @param[out] ArraySignatureClose String to the close of array signature. + + @retval EFI_SUCCESS Index is found. + @retval EFI_NOT_FOUND The non-array configure language string is retured. + @retval EFI_INVALID_PARAMETER The format of input ConfigureLang is wrong. + @retval Others Errors occur. + +**/ +EFI_STATUS +IsRedpathArray ( + IN EFI_STRING ConfigureLang, + OUT EFI_STRING *ArraySignatureOpen OPTIONAL, + OUT EFI_STRING *ArraySignatureClose OPTIONAL + ) +{ + CHAR16 *IndexString; + + if (ConfigureLang == NULL) { + return EFI_INVALID_PARAMETER; + } + if (ArraySignatureOpen != NULL) { + *ArraySignatureOpen = NULL; + } + if (ArraySignatureClose != NULL) { + *ArraySignatureClose = NULL; + } + + // + // looking for index signature "{"" + // + IndexString = StrStr (ConfigureLang, BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE); + if (IndexString != NULL) { + if (ArraySignatureOpen != NULL) { + *ArraySignatureOpen = IndexString; + } + // + // Skip "{" + // + IndexString = IndexString + StrLen (BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE); + // + // Looking for "}" + // + IndexString = StrStr (IndexString, BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_END_SIGNATURE); + if (IndexString == NULL) { + return EFI_INVALID_PARAMETER; + } + if (ArraySignatureClose != NULL) { + *ArraySignatureClose = IndexString; + } + return EFI_SUCCESS; + } + return EFI_NOT_FOUND; +} + +/** + + Get number of node from the string. Node is seperated by '/'. + + @param[in] NodeString The node string to parse. + + @retval UINTN Number of nodes in the string. + +**/ +UINTN +GetNumberOfRedpathNodes ( + IN EFI_STRING NodeString + ) +{ + UINTN Index; + UINTN NumberNodes; + UINTN StringLen; + + NumberNodes = 0; + StringLen = StrLen (NodeString); + Index = 1; // ConfigLang always starts with '/'. + while (Index < StringLen) { + if (*(NodeString + Index) == L'/') { + NumberNodes ++; + } + Index ++; + }; + NumberNodes ++; + + return (NumberNodes); +} + +/** + + Get the node string by index + + @param[in] NodeString The node string to parse. + @param[in] Index Zero-based index of the node. + @param[out] EndOfNodePtr Pointer to receive the poitner to + the last character of node string. + + @retval EFI_STRING the begining of the node string. + +**/ +EFI_STRING +GetRedpathNodeByIndex ( + IN EFI_STRING NodeString, + IN UINTN Index, + OUT EFI_STRING *EndOfNodePtr OPTIONAL + ) +{ + UINTN NumberNodes; + UINTN StringLen; + UINTN StringIndex; + EFI_STRING NodeStart; + EFI_STRING NodeEnd; + + NumberNodes = 0; + StringLen = StrLen (NodeString); + StringIndex = 1; // ConfigLang always starts with '/'. + NodeStart = NodeString; + if (EndOfNodePtr != NULL) { + *EndOfNodePtr = NULL; + } + while (StringIndex < StringLen) { + if (*(NodeString + StringIndex) == L'/') { + NodeEnd = NodeString + StringIndex - 1; + if (NumberNodes == Index) { + if (EndOfNodePtr != NULL) { + *EndOfNodePtr = NodeEnd; + } + return NodeStart; + } else { + NodeStart = NodeString + StringIndex + 1; } + } + StringIndex ++; + }; + return (NULL); +} + +/** + + Find array index from given configure language string. + + @param[in] ConfigureLang Configure language string to parse. + @param[out] UnifiedConfigureLang The configure language in array. + @param[out] Index The array index number. + + @retval EFI_SUCCESS Index is found. + @retval EFI_NOT_FOUND The non-array configure language string is retured. + @retval EFI_INVALID_PARAMETER The format of input ConfigureLang is wrong. + @retval Others Errors occur. + +**/ +EFI_STATUS +GetArrayIndexFromArrayTypeConfigureLang ( + IN CHAR16 *ConfigureLang, + OUT CHAR16 **UnifiedConfigureLang, + OUT UINTN *Index + ) +{ + EFI_STATUS Status; + CHAR16 *TmpConfigureLang; + CHAR16 *ArrayOpenStr; + CHAR16 *ArrayCloseStr; + INTN StringIndex; + + if (ConfigureLang == NULL || UnifiedConfigureLang == NULL || Index == NULL) { + return EFI_INVALID_PARAMETER; + } + + TmpConfigureLang = AllocateCopyPool (StrSize (ConfigureLang), ConfigureLang); + if (TmpConfigureLang == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = IsRedpathArray (TmpConfigureLang, &ArrayOpenStr, &ArrayCloseStr); + if (!EFI_ERROR (Status)) { + // + // Append '\0' for converting decimal string to integer. + // + ArrayCloseStr[0] = '\0'; + + // + // Convert decimal string to integer + // + *Index = StrDecimalToUintn (ArrayOpenStr + StrLen (BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE)); + + // + // Resotre the '}' character and remove rest of string. + // + ArrayCloseStr[0] = L'}'; + ArrayCloseStr[1] = '\0'; + *UnifiedConfigureLang = TmpConfigureLang; + } else { + if (Status == EFI_NOT_FOUND) { + // + // This is not the redpath array. Search "/" for the parent root. + // + *Index = 0; + StringIndex = StrLen (TmpConfigureLang) - 1; + while (StringIndex >= 0 && *(TmpConfigureLang + StringIndex) != '/') { + StringIndex --; + }; + if (StringIndex >= 0 ) { + *(TmpConfigureLang + StringIndex) = '\0'; + *UnifiedConfigureLang = TmpConfigureLang; + Status = EFI_SUCCESS; + } else { + Status = EFI_INVALID_PARAMETER; + } + } + } + return Status; +} + +/** + + Clone the configure language list. + + @param[in] ConfigureLangList The source REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST. + @param[out] DestConfigureLangList The destination REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST. + + @retval EFI_SUCCESS REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST is copied. + @retval Others Errors occur. + +**/ +EFI_STATUS +CopyConfiglanguageList ( + IN REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST *SourceConfigureLangList, + OUT REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST *DestConfigureLangList + ) +{ + UINTN Index; + + if (SourceConfigureLangList == NULL || DestConfigureLangList == NULL) { + return EFI_INVALID_PARAMETER; + } + DestConfigureLangList->Count = SourceConfigureLangList->Count; + DestConfigureLangList->List = + (REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG *)AllocateZeroPool (sizeof (REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG) * DestConfigureLangList->Count); + if (DestConfigureLangList->List == NULL) { + DEBUG ((DEBUG_ERROR, "%a, Fail to allocate memory for REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG.\n", __FUNCTION__)); + return EFI_OUT_OF_RESOURCES; + } + for (Index = 0; Index < SourceConfigureLangList->Count; Index++) { + DestConfigureLangList->List [Index].Index = SourceConfigureLangList->List[Index].Index; + DestConfigureLangList->List [Index].ConfigureLang = + (EFI_STRING)AllocateCopyPool(StrSize(SourceConfigureLangList->List[Index].ConfigureLang), (VOID *)SourceConfigureLangList->List[Index].ConfigureLang); + } + return EFI_SUCCESS; +} + +/** + + Clone the configure language list. + + @param[in] ConfigureLang The pointer to configuration language. + + @retval UINTN The index of collection member instance. + Value of 0 means no instance is found. +**/ +UINTN +ConfiglanguageGetInstanceIndex ( + IN EFI_STRING ConfigureLang + ) +{ + INTN LeftBracketIndex; + INTN RightBracketIndex; + INTN Index; + UINT64 Instance; + EFI_STATUS Status; + + if (ConfigureLang == NULL) { + return 0; + } + LeftBracketIndex = 0; + RightBracketIndex = 0; + Index = StrLen (ConfigureLang) - 1; + while (Index >= 0) { + if (*(ConfigureLang + Index) == L'{') { + LeftBracketIndex = Index; + break; + } + if (*(ConfigureLang + Index) == L'}') { + RightBracketIndex = Index; + } + Index --; + }; + if ((RightBracketIndex - LeftBracketIndex) <= 1) { + return 0; + } + *(ConfigureLang + RightBracketIndex) = 0; + Status = StrDecimalToUint64S (ConfigureLang + LeftBracketIndex + 1, NULL, &Instance); + if (EFI_ERROR(Status)) { + Instance = 0; + } + // + // Restore right curly bracket. + // + *(ConfigureLang + RightBracketIndex) = L'}'; + return (UINTN)Instance; +} + +/** + + Destroy the configure language list. + + @param[in] ConfigureLangList The REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST + instance to destroy. + + @retval EFI_SUCCESS REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST is copied. + @retval Others Errors occur. + +**/ +EFI_STATUS +DestroyConfiglanguageList ( + IN REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST *ConfigureLangList + ) +{ + UINTN Index; + + if (ConfigureLangList == NULL) { + return EFI_INVALID_PARAMETER; + } + if (ConfigureLangList->List != NULL) { + for (Index = 0; Index < ConfigureLangList->Count; Index++) { + if (ConfigureLangList->List [Index].ConfigureLang != NULL) { + FreePool (ConfigureLangList->List [Index].ConfigureLang); + } + } + FreePool (ConfigureLangList->List); + ConfigureLangList->List = NULL; + } + + return EFI_SUCCESS; +} + +/** + + Set the node instance. + + @param[in] DestConfigLang Pointer to the node's configure language string. + The memory pointed by ConfigLang must be allocated + through memory allocation interface. Becasue we will replace + the pointer in this function. + @param[in] MaxtLengthConfigLang The maximum length of ConfigLang. + @param[in] ConfigLangInstance Pointer to Collection member instance. + + @retval EFI_SUCCESS The instance is inserted to the configure language. + @retval Others Errors occur. + +**/ +EFI_STATUS +SetResourceConfigLangMemberInstance ( + IN EFI_STRING *DestConfigLang, + IN UINTN MaxtLengthConfigLang, + IN REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG *ConfigLangInstance + ) +{ + EFI_STRING ThisConfigLang; + EFI_STRING NewConfigLang; + CHAR16 InstanceStr [10]; + INTN Index; + UINTN Length; + UINTN MaxStrLength; + + if (DestConfigLang == NULL || ConfigLangInstance == NULL) { + return EFI_INVALID_PARAMETER; + } + UnicodeSPrint ((CHAR16 *)&InstanceStr, 10, L"%d", ConfigLangInstance->Index); + + ThisConfigLang = *DestConfigLang; + if (ThisConfigLang [0] == 0) { + // + // Return ConfigLangInstance->ConfigureLang + // + if (ConfigLangInstance->ConfigureLang == NULL) { + return EFI_INVALID_PARAMETER; + } else { + StrCatS(*DestConfigLang, MaxtLengthConfigLang, ConfigLangInstance->ConfigureLang); + return EFI_SUCCESS; + } + } + + MaxStrLength = StrSize (ThisConfigLang) + StrSize ((EFI_STRING)&InstanceStr); + NewConfigLang = ThisConfigLang; + if (MaxtLengthConfigLang < MaxStrLength) { + NewConfigLang = (EFI_STRING)AllocateZeroPool(MaxStrLength); + if (NewConfigLang == NULL) { + DEBUG ((DEBUG_ERROR, "%a, Fail to allocate memory for NewConfigLang.\n", __FUNCTION__)); + return EFI_OUT_OF_RESOURCES; + } + } + // + // Search the last "{" + // + Index = StrLen (ThisConfigLang) - 1; + while ((ThisConfigLang[Index] != '{') && (Index >= 0)) { + Index --; + }; + if (Index == -1) { + if (NewConfigLang != ThisConfigLang) { + FreePool(NewConfigLang); + } + return EFI_NOT_FOUND; + } + + // + // Copy the string to a new string. + // + Length = 0; + while (Index >= 0) { + NewConfigLang [Index] = ThisConfigLang[Index]; + Index --; + Length ++; + }; + UnicodeSPrint ((CHAR16 *)(NewConfigLang + Length), MaxStrLength, L"%d", ConfigLangInstance->Index); + StrCatS (NewConfigLang, MaxStrLength, L"}"); + if (NewConfigLang != ThisConfigLang) { + FreePool (ThisConfigLang); + } + *DestConfigLang = NewConfigLang; + return EFI_SUCCESS; +} + +/** + + Search HII database with given Configure Language pattern. Data is handled and + returned in array. + + @param[in] Schema The schema to search. + @param[in] Version The schema version. + @param[in] Pattern Configure Language pattern to search. + @param[out] UnifiedConfigureLangList The data returned by HII database. + + @retval EFI_SUCCESS Data is found and returned. + @retval Others Errors occur. + +**/ +EFI_STATUS +RedfishFeatureGetUnifiedArrayTypeConfigureLang ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING Pattern, OPTIONAL + OUT REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST *UnifiedConfigureLangList + ) +{ + EFI_STATUS Status; + EFI_STRING *ConfigureLangList; + UINTN Count; + UINTN Index; + UINTN Index2; + UINTN ArrayIndex; + EFI_STRING UnifiedConfigureLang; + BOOLEAN Duplicated; + REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG UnifiedConfigureLangPool[BIOS_CONFIG_TO_REDFISH_REDPATH_POOL_SIZE]; + + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || UnifiedConfigureLangList == NULL) { + return EFI_INVALID_PARAMETER; + } + + UnifiedConfigureLangList->Count = 0; + UnifiedConfigureLangList->List = NULL; + ZeroMem (UnifiedConfigureLangPool, sizeof (UnifiedConfigureLangPool)); + + Status = RedfishPlatformConfigGetConfigureLang (Schema, Version, Pattern, &ConfigureLangList, &Count); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, RedfishFeatureGetConfigureLangRegex failed: %r\n", __FUNCTION__, Status)); + return Status; + } + + if (Count == 0) { + return EFI_NOT_FOUND; + } + + for (Index = 0; Index < Count; Index++) { + Status = GetArrayIndexFromArrayTypeConfigureLang (ConfigureLangList[Index], &UnifiedConfigureLang, &ArrayIndex); + if (EFI_ERROR (Status) && Status == EFI_INVALID_PARAMETER) { + ASSERT (FALSE); + continue; + } + + // + // Check if this configure language is duplicated. + // + Duplicated = FALSE; + for (Index2 = 0; Index2 < BIOS_CONFIG_TO_REDFISH_REDPATH_POOL_SIZE; Index2++) { + if (UnifiedConfigureLangPool[Index2].ConfigureLang == NULL) { + break; + } + + if (StrCmp (UnifiedConfigureLangPool[Index2].ConfigureLang, UnifiedConfigureLang) == 0) { + Duplicated = TRUE; + break; + } + } + + if (Duplicated) { + FreePool (UnifiedConfigureLang); + continue; + } + + if (UnifiedConfigureLangList->Count >= BIOS_CONFIG_TO_REDFISH_REDPATH_POOL_SIZE) { + FreePool (UnifiedConfigureLang); + Status = EFI_BUFFER_TOO_SMALL; + break; + } + + // + // New configure language. Keep it in Pool + // + + UnifiedConfigureLangPool[UnifiedConfigureLangList->Count].ConfigureLang = UnifiedConfigureLang; + UnifiedConfigureLangPool[UnifiedConfigureLangList->Count].Index = ArrayIndex; + ++UnifiedConfigureLangList->Count; + } + + FreePool (ConfigureLangList); + + // + // Prepare the result to caller. + // + UnifiedConfigureLangList->List = AllocateCopyPool (sizeof (REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG) * UnifiedConfigureLangList->Count, UnifiedConfigureLangPool); + + return Status; +} + +/** + + Find "ETag" and "Location" from either HTTP header or Redfish response. + + @param[in] Response HTTP response + @param[out] Etag String buffer to return ETag + @param[out] Location String buffer to return Location + + @retval EFI_SUCCESS Data is found and returned. + @retval Others Errors occur. + +**/ +EFI_STATUS +GetEtagAndLocation ( + IN REDFISH_RESPONSE *Response, + OUT CHAR8 **Etag, OPTIONAL + OUT EFI_STRING *Location OPTIONAL + ) +{ + EDKII_JSON_VALUE JsonValue; + EDKII_JSON_VALUE OdataValue; + CHAR8 *OdataString; + CHAR8 *AsciiLocation; + EFI_HTTP_HEADER *Header; + EFI_STATUS Status; + + if (Response == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Etag == NULL && Location == NULL) { + return EFI_SUCCESS; + } + + Status = EFI_SUCCESS; + + if (Etag != NULL) { + *Etag = NULL; + + if (*(Response->StatusCode) == HTTP_STATUS_200_OK) { + Header = HttpFindHeader (Response->HeaderCount, Response->Headers, HTTP_HEADER_ETAG); + if (Header != NULL) { + *Etag = AllocateCopyPool (AsciiStrSize (Header->FieldValue), Header->FieldValue); + ASSERT (*Etag != NULL); + } + } + + // + // No header is returned. Search payload for location. + // + if (*Etag == NULL && Response->Payload != NULL) { + JsonValue = RedfishJsonInPayload (Response->Payload); + if (JsonValue != NULL) { + OdataValue = JsonObjectGetValue (JsonValueGetObject (JsonValue), "@odata.etag"); + if (OdataValue != NULL) { + OdataString = (CHAR8 *)JsonValueGetAsciiString (OdataValue); + if (OdataString != NULL) { + *Etag = AllocateCopyPool (AsciiStrSize (OdataString), OdataString); + ASSERT (*Etag != NULL); + } + } + + JsonValueFree (JsonValue); + } + } + + if (*Etag == NULL) { + Status = EFI_NOT_FOUND; + } + } + + if (Location != NULL) { + *Location = NULL; + + if (*(Response->StatusCode) == HTTP_STATUS_200_OK) { + Header = HttpFindHeader (Response->HeaderCount, Response->Headers, HTTP_HEADER_LOCATION); + if (Header != NULL) { + AsciiLocation = AllocateCopyPool (AsciiStrSize (Header->FieldValue), Header->FieldValue); + ASSERT (AsciiLocation != NULL); + } + } + + // + // No header is returned. Search payload for location. + // + if (*Location == NULL && Response->Payload != NULL) { + JsonValue = RedfishJsonInPayload (Response->Payload); + if (JsonValue != NULL) { + OdataValue = JsonObjectGetValue (JsonValueGetObject (JsonValue), "@odata.id"); + if (OdataValue != NULL) { + OdataString = (CHAR8 *)JsonValueGetAsciiString (OdataValue); + if (OdataString != NULL) { + AsciiLocation = AllocateCopyPool (AsciiStrSize (OdataString), OdataString); + ASSERT (AsciiLocation != NULL); + } + } + + JsonValueFree (JsonValue); + } + } + + if (AsciiLocation != NULL) { + *Location = StrAsciiToUnicode (AsciiLocation); + FreePool (AsciiLocation); + } else { + Status = EFI_NOT_FOUND; + } + } + + return Status; +} +/** + + Create HTTP payload and send them to redfish service with PATCH method. + + @param[in] Service Redfish service. + @param[in] TargetPayload Target payload + @param[in] Json Data in JSON format. + @param[out] Etag Returned ETAG string from Redfish service. + + @retval EFI_SUCCESS Data is sent to redfish service successfully. + @retval Others Errors occur. + +**/ +EFI_STATUS +CreatePayloadToPatchResource ( + IN REDFISH_SERVICE *Service, + IN REDFISH_PAYLOAD *TargetPayload, + IN CHAR8 *Json, + OUT CHAR8 **Etag + ) +{ + REDFISH_PAYLOAD Payload; + EDKII_JSON_VALUE ResourceJsonValue; + REDFISH_RESPONSE PostResponse; + EFI_STATUS Status; + + if (Service == NULL || TargetPayload == NULL || IS_EMPTY_STRING (Json) || Etag == NULL) { + return EFI_INVALID_PARAMETER; + } + + ResourceJsonValue = JsonLoadString (Json, 0, NULL); + Payload = RedfishCreatePayload (ResourceJsonValue, Service); + if (Payload == NULL) { + DEBUG ((DEBUG_ERROR, "%a:%d Failed to create JSON payload from JSON value!\n",__FUNCTION__, __LINE__)); + Status = EFI_DEVICE_ERROR; + goto EXIT_FREE_JSON_VALUE; + } + + ZeroMem (&PostResponse, sizeof (REDFISH_RESPONSE)); + Status = RedfishPatchToPayload (TargetPayload, Payload, &PostResponse); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:%d Failed to PATCH payload to Redfish service.\n",__FUNCTION__, __LINE__)); + goto EXIT_FREE_JSON_VALUE; + } + + // + // Find ETag + // + Status = GetEtagAndLocation (&PostResponse, Etag, NULL); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + } + + RedfishFreeResponse ( + PostResponse.StatusCode, + PostResponse.HeaderCount, + PostResponse.Headers, + PostResponse.Payload + ); + +EXIT_FREE_JSON_VALUE: + if (Payload != NULL) { + RedfishCleanupPayload (Payload); + } + + JsonValueFree (ResourceJsonValue); + + return Status; +} + +/** + + Create HTTP payload and send them to redfish service with POST method. + + @param[in] Service Redfish service. + @param[in] TargetPayload Target payload + @param[in] Json Data in JSON format. + @param[out] Location Returned location string from Redfish service. + @param[out] Etag Returned ETAG string from Redfish service. + + @retval EFI_SUCCESS Data is sent to redfish service successfully. + @retval Others Errors occur. + +**/ +EFI_STATUS +CreatePayloadToPostResource ( + IN REDFISH_SERVICE *Service, + IN REDFISH_PAYLOAD *TargetPayload, + IN CHAR8 *Json, + OUT EFI_STRING *Location, + OUT CHAR8 **Etag + ) +{ + REDFISH_PAYLOAD Payload; + EDKII_JSON_VALUE ResourceJsonValue; + REDFISH_RESPONSE PostResponse; + EFI_STATUS Status; + + if (Service == NULL || TargetPayload == NULL || IS_EMPTY_STRING (Json) || Location == NULL || Etag == NULL) { + return EFI_INVALID_PARAMETER; + } + + ResourceJsonValue = JsonLoadString (Json, 0, NULL); + Payload = RedfishCreatePayload (ResourceJsonValue, Service); + if (Payload == NULL) { + DEBUG ((DEBUG_ERROR, "%a:%d Failed to create JSON payload from JSON value!\n",__FUNCTION__, __LINE__)); + Status = EFI_DEVICE_ERROR; + goto EXIT_FREE_JSON_VALUE; + } + + ZeroMem (&PostResponse, sizeof (REDFISH_RESPONSE)); + Status = RedfishPostToPayload (TargetPayload, Payload, &PostResponse); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:%d Failed to POST Attribute Registry to Redfish service.\n",__FUNCTION__, __LINE__)); + goto EXIT_FREE_JSON_VALUE; + } + + // + // per Redfish spec. the URL of new eresource will be returned in "Location" header. + // + Status = GetEtagAndLocation (&PostResponse, Etag, Location); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + } + + RedfishFreeResponse ( + PostResponse.StatusCode, + PostResponse.HeaderCount, + PostResponse.Headers, + PostResponse.Payload + ); + + RedfishCleanupPayload (Payload); + +EXIT_FREE_JSON_VALUE: + JsonValueFree (ResourceJsonValue); + + return Status; +} + +/** + + Return redfish URI by given config language. It's call responsibility to release returned buffer. + + @param[in] ConfigLang ConfigLang to search. + + @retval NULL Can not find redfish uri. + @retval Other redfish uri is returned. + +**/ +EFI_STRING +RedfishGetUri ( + IN EFI_STRING ConfigLang + ) +{ + EFI_STATUS Status; + EFI_STRING Target; + EFI_STRING Found; + EFI_STRING TempStr; + EFI_STRING ResultStr; + EFI_STRING Head; + EFI_STRING CloseBracket; + UINTN TempStrSize; + UINTN RemainingLen; + UINTN ConfigLangLen; + + Status = RedfishLocateProtocol ((VOID **)&mConfigLangMapProtocol, &gEdkIIRedfishConfigLangMapProtocolGuid); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, fail to locate gEdkIIRedfishConfigLangMapProtocolGuid: %r\n", __FUNCTION__, Status)); + return NULL; + } + + DEBUG ((REDFISH_DEBUG_TRACE, "%a, Get: %s\n", __FUNCTION__, ConfigLang)); + + CloseBracket = StrStr (ConfigLang, L"{"); + if (CloseBracket == NULL) { + return AllocateCopyPool (StrSize (ConfigLang), ConfigLang); + } + + // + // Remove leading "/v1" or "/redfish/v1" because we don't code + // configure language in this way. + // + Head = StrStr (ConfigLang, REDFISH_ROOT_PATH_UNICODE); + if (Head == NULL) { + Head = ConfigLang; + } else { + Head += 3; + } + + ResultStr = AllocateZeroPool (sizeof (CHAR16) * MAX_REDFISH_URL_LEN); + if (ResultStr == NULL) { + return NULL; + } + + // + // Go though ConfigLang and replace each {} with URL + // + do { + ConfigLangLen = StrLen (Head); + Target = CloseBracket; + + // + // Look for next ConfigLang + // + do { + Target += 1; + } while (*Target != '\0' && *Target != '}'); + + // + // Invalid format. No '}' found + // + if (*Target == '\0') { + DEBUG ((DEBUG_ERROR, "%a, invalid format: %s\n", __FUNCTION__, ConfigLang)); + return NULL; + } + + // + // Copy current ConfigLang to temporary string and do a query + // + Target += 1; + RemainingLen = StrLen (Target); + TempStrSize = (ConfigLangLen - RemainingLen + 1) * sizeof (CHAR16); + TempStr = AllocateCopyPool (TempStrSize, Head); + if (TempStr == NULL) { + return NULL; + } + TempStr[ConfigLangLen - RemainingLen] = '\0'; + + Status = mConfigLangMapProtocol->Get ( + mConfigLangMapProtocol, + RedfishGetTypeConfigLang, + TempStr, + &Found + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, Can not find: %s\n", __FUNCTION__, TempStr)); + return NULL; + } + + DEBUG ((REDFISH_DEBUG_TRACE, "%a, Found: %s\n", __FUNCTION__, Found)); + + // + // Keep result in final string pool + // + StrCatS (ResultStr, MAX_REDFISH_URL_LEN, Found); + FreePool (TempStr); + + // + // Prepare for next ConfigLang + // + Head = Target; + CloseBracket = StrStr (Head, L"{"); + } while (CloseBracket != NULL); + + // + // String which has no ConfigLang remaining + // + if (Head != '\0') { + StrCatS (ResultStr, MAX_REDFISH_URL_LEN, Head); + } + + DEBUG ((REDFISH_DEBUG_TRACE, "%a, return: %s\n", __FUNCTION__, ResultStr)); + + return ResultStr; +} + +/** + + Return config language by given URI. It's call responsibility to release returned buffer. + + @param[in] Uri Uri to search. + + @retval NULL Can not find redfish uri. + @retval Other redfish uri is returned. + +**/ +EFI_STRING +RedfishGetConfigLanguage ( + IN EFI_STRING Uri + ) +{ + EFI_STATUS Status; + EFI_STRING ConfigLang; + + if (IS_EMPTY_STRING (Uri)) { + return NULL; + } + + DEBUG ((REDFISH_DEBUG_TRACE, "%a, search config lang for URI: %s\n", __FUNCTION__, Uri)); + + Status = RedfishLocateProtocol ((VOID **)&mConfigLangMapProtocol, &gEdkIIRedfishConfigLangMapProtocolGuid); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, fail to locate gEdkIIRedfishConfigLangMapProtocolGuid: %r\n", __FUNCTION__, Status)); + return NULL; + } + + ConfigLang = NULL; + Status = mConfigLangMapProtocol->Get ( + mConfigLangMapProtocol, + RedfishGetTypeUri, + Uri, + &ConfigLang + ); + + + return ConfigLang; +} + +/** + + Return config language from given URI and prperty name. It's call responsibility to release returned buffer. + + @param[in] Uri The URI to match + @param[in] PropertyName The property name of resource. This is optional. + + @retval NULL Can not find redfish uri. + @retval Other redfish uri is returned. + +**/ +EFI_STRING +GetConfigureLang ( + IN CHAR8 *Uri, + IN CHAR8 *PropertyName OPTIONAL + ) +{ + EFI_STRING ConfigLang; + UINTN StringSize; + EFI_STRING ResultStr; + EFI_STRING UnicodeUri; + EFI_STATUS Status; + + if (IS_EMPTY_STRING (Uri)) { + return NULL; + } + + StringSize = AsciiStrSize (Uri); + UnicodeUri = AllocatePool (StringSize * sizeof (CHAR16)); + if (UnicodeUri == NULL) { + return NULL; + } + + Status = AsciiStrToUnicodeStrS (Uri, UnicodeUri, StringSize); + if (EFI_ERROR (Status)) { + return NULL; + } + + ConfigLang = RedfishGetConfigLanguage (UnicodeUri); + if (ConfigLang == NULL) { + return NULL; + } + + if (IS_EMPTY_STRING (PropertyName)) { + return ConfigLang; + } + + StringSize = StrSize (ConfigLang) + ((AsciiStrLen (PropertyName) + 1) * sizeof (CHAR16)); + ResultStr = AllocatePool (StringSize); + if (ResultStr == NULL) { + return NULL; + } + + UnicodeSPrint (ResultStr, StringSize, L"%s/%a", ConfigLang, PropertyName); + + return ResultStr; +} + +/** + + Save Redfish URI in database for further use. + + @param[in] ConfigLang ConfigLang to save + @param[in] Uri Redfish Uri to save + + @retval EFI_INVALID_PARAMETR SystemId is NULL or EMPTY + @retval EFI_SUCCESS Redfish uri is saved + +**/ +EFI_STATUS +RedfisSetRedfishUri ( + IN EFI_STRING ConfigLang, + IN EFI_STRING Uri + ) +{ + EFI_STATUS Status; + + if (IS_EMPTY_STRING (ConfigLang) || IS_EMPTY_STRING (Uri)) { + return EFI_INVALID_PARAMETER; + } + + Status = RedfishLocateProtocol ((VOID **)&mConfigLangMapProtocol, &gEdkIIRedfishConfigLangMapProtocolGuid); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, fail to locate gEdkIIRedfishConfigLangMapProtocolGuid: %r\n", __FUNCTION__, Status)); + return Status; + } + + DEBUG ((REDFISH_DEBUG_TRACE, "%a, Saved: %s -> %s\n", __FUNCTION__, ConfigLang, Uri)); + + return mConfigLangMapProtocol->Set (mConfigLangMapProtocol, ConfigLang, Uri); +} + +/** + + Get @odata.id from give HTTP payload. It's call responsibility to release returned buffer. + + @param[in] Payload HTTP payload + + @retval NULL Can not find @odata.id from given payload. + @retval Others odata.id string is returned. + +**/ +EFI_STRING +GetOdataId ( + IN REDFISH_PAYLOAD *Payload + ) +{ + EDKII_JSON_VALUE *JsonValue; + EDKII_JSON_VALUE *OdataId; + EFI_STRING OdataIdString; + + if (Payload == NULL) { + return NULL; + } + + JsonValue = RedfishJsonInPayload (Payload); + if (!JsonValueIsObject (JsonValue)) { + return NULL; + } + + OdataId = JsonObjectGetValue (JsonValueGetObject (JsonValue), "@odata.id"); + if (!JsonValueIsString (OdataId)) { + return NULL; + } + + OdataIdString = JsonValueGetUnicodeString (OdataId); + if (OdataIdString == NULL) { + return NULL; + } + + return AllocateCopyPool (StrSize (OdataIdString), OdataIdString); +} + + +/** + + Get the property name by given Configure Langauge. + + @param[in] ResourceUri URI of root of resource. + @param[in] ConfigureLang Configure Language string. + + @retval EFI_STRING Pointer to property name. + @retval NULL There is error. + +**/ +EFI_STRING +GetPropertyFromConfigureLang ( + IN EFI_STRING ResourceUri, + IN EFI_STRING ConfigureLang + ) +{ + EFI_STATUS Status; + EFI_STRING TempString; + + if (ConfigureLang == NULL || ResourceUri == NULL) { + return NULL; + } + + Status = IsRedpathArray (ConfigureLang, NULL, &TempString); + if (!EFI_ERROR(Status)) { + TempString += 2; // Advance two characters for '}' and '/' + return TempString; + } + if (Status != EFI_NOT_FOUND) { + return NULL; + } + // + // The ConigLang has no '{}' + // + if (GetNumberOfRedpathNodes (ConfigureLang) == 1) { + return NULL; + } + + if (GetRedpathNodeByIndex (ConfigureLang, 0, &TempString) == NULL) { + return NULL; + } + // + // Advance two characters to the starting + // pointer of next node. + // + return TempString + 2; +} + +/** + + Get the property value in string type. + + @param[in] Schema Schema of this property. + @param[in] Version Schema version. + @param[in] PropertyName Property name. + @param[in] ConfigureLang Configure Language of this property. + + @retval CHAR8* Pointer to the CHAR8 buffer. + @retval NULL There is error. + +**/ +CHAR8 * +GetPropertyStringValue ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING PropertyName, + IN EFI_STRING ConfigureLang + ) +{ + EFI_STATUS Status; + EDKII_REDFISH_VALUE RedfishValue; + EFI_STRING ConfigureLangBuffer; + UINTN BufferSize; + CHAR8 *AsciiStringValue; + + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) { + return NULL; + } + + // + // Configure Language buffer. + // + BufferSize = sizeof (CHAR16) * MAX_CONF_LANG_LEN; + ConfigureLangBuffer = AllocatePool (BufferSize); + if (ConfigureLangBuffer == NULL) { + return NULL; + } + + UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang, PropertyName); + Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLangBuffer, &RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status)); + return NULL; + } + + if (RedfishValue.Type != REDFISH_VALUE_TYPE_STRING) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string type\n", __FUNCTION__, Schema, Version, ConfigureLang)); + return NULL; + } + + AsciiStringValue = AllocateCopyPool (AsciiStrSize (RedfishValue.Value.Buffer), RedfishValue.Value.Buffer); + ASSERT (AsciiStringValue != NULL); + + return AsciiStringValue; +} + +/** + + Get the property value in numeric type. + + @param[in] Schema Schema of this property. + @param[in] Version Schema version. + @param[in] PropertyName Property name. + @param[in] ConfigureLang Configure Language of this property. + + @retval INT64* Pointer to the INT64 value. + @retval NULL There is error. + +**/ +INT64 * +GetPropertyNumericValue ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING PropertyName, + IN EFI_STRING ConfigureLang + ) +{ + EFI_STATUS Status; + EDKII_REDFISH_VALUE RedfishValue; + EFI_STRING ConfigureLangBuffer; + UINTN BufferSize; + INT64 *ResultValue; + + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) { + return NULL; + } + + // + // Configure Language buffer. + // + BufferSize = sizeof (CHAR16) * MAX_CONF_LANG_LEN; + ConfigureLangBuffer = AllocatePool (BufferSize); + if (ConfigureLangBuffer == NULL) { + return NULL; + } + + UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang, PropertyName); + Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLangBuffer, &RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status)); + return NULL; + } + + if (RedfishValue.Type != REDFISH_VALUE_TYPE_INTEGER) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not numeric type\n", __FUNCTION__, Schema, Version, ConfigureLang)); + return NULL; + } + + ResultValue = AllocatePool (sizeof (INT64)); + ASSERT (ResultValue != NULL); + if (ResultValue == NULL) { + return NULL; + } + + *ResultValue = RedfishValue.Value.Integer; + + return ResultValue; +} + +/** + + Get the property value in Boolean type. + + @param[in] Schema Schema of this property. + @param[in] Version Schema version. + @param[in] PropertyName Property name. + @param[in] ConfigureLang Configure Language of this property. + + @retval BOOLEAN Boolean value returned by this property. + +**/ +BOOLEAN * +GetPropertyBooleanValue ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING PropertyName, + IN EFI_STRING ConfigureLang + ) +{ + EFI_STATUS Status; + EDKII_REDFISH_VALUE RedfishValue; + EFI_STRING ConfigureLangBuffer; + UINTN BufferSize; + BOOLEAN *ResultValue; + + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) { + return NULL; + } + + // + // Configure Language buffer. + // + BufferSize = sizeof (CHAR16) * MAX_CONF_LANG_LEN; + ConfigureLangBuffer = AllocatePool (BufferSize); + if (ConfigureLangBuffer == NULL) { + return NULL; + } + + UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang, PropertyName); + Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLangBuffer, &RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status)); + return NULL; + } + + if (RedfishValue.Type != REDFISH_VALUE_TYPE_BOOLEAN) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not boolean type\n", __FUNCTION__, Schema, Version, ConfigureLang)); + return NULL; + } + + ResultValue = AllocatePool (sizeof (BOOLEAN)); + ASSERT (ResultValue != NULL); + if (ResultValue == NULL) { + return NULL; + } + + *ResultValue = RedfishValue.Value.Boolean; + + return ResultValue; +} + +/** + + Return the last string of configure language. Any modification to returned + string will change ConfigureLanguage. + + @param[in] ConfigureLanguage Configure language string + + @retval EFI_STRING Attribute name is returned + @retval NULL Error occurs + +**/ +EFI_STRING +GetAttributeNameFromConfigLanguage ( + IN EFI_STRING ConfigureLanguage + ) +{ + UINTN StringLen; + UINTN Index; + + if (IS_EMPTY_STRING (ConfigureLanguage)) { + return NULL; + } + + StringLen = StrLen (ConfigureLanguage); + for (Index = StringLen - 1; Index >= 0; Index--) { + if (ConfigureLanguage[Index] == '/') { + return &ConfigureLanguage[Index + 1]; + } + } + + return NULL; +} + +/** + + Get the property string value in array type. + + @param[in] Schema Schema of this property. + @param[in] Version Schema version. + @param[in] PropertyName Property name. + @param[in] ConfigureLang Configure Language of this property. + @param[out] ArraySize The size of returned array. + + @retval CHAR8 ** Returned string array. NULL while error happens. + +**/ +CHAR8 ** +GetPropertyStringArrayValue ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING PropertyName, + IN EFI_STRING ConfigureLang, + OUT UINTN *ArraySize + ) +{ + EFI_STATUS Status; + EDKII_REDFISH_VALUE RedfishValue; + EFI_STRING ConfigureLangBuffer; + UINTN BufferSize; + CHAR8 **StringArray; + UINTN Index; + + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName) || ArraySize == NULL) { + return NULL; + } + + *ArraySize = 0; + + // + // Configure Language buffer. + // + BufferSize = sizeof (CHAR16) * MAX_CONF_LANG_LEN; + ConfigureLangBuffer = AllocatePool (BufferSize); + if (ConfigureLangBuffer == NULL) { + DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__)); + return NULL; + } + + UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang, PropertyName); + Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLangBuffer, &RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status)); + return NULL; + } + + if (RedfishValue.Type != REDFISH_VALUE_TYPE_STRING_ARRAY) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string array type\n", __FUNCTION__, Schema, Version, ConfigureLang)); + return NULL; + } + + StringArray = AllocatePool (sizeof (CHAR8 *) * RedfishValue.ArrayCount); + if (StringArray == NULL) { + DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__)); + return NULL; + } + + *ArraySize = RedfishValue.ArrayCount; + for (Index = 0; Index < RedfishValue.ArrayCount; Index++) { + StringArray[Index] = RedfishValue.Value.StringArray[Index]; + } + + return StringArray; +} + +/** + + Get the property numeric value in array type. + + @param[in] Schema Schema of this property. + @param[in] Version Schema version. + @param[in] PropertyName Property name. + @param[in] ConfigureLang Configure Language of this property. + @param[out] ArraySize The size of returned array. + + @retval INT64 * Returned integer array. NULL while error happens. + +**/ +INT64 * +GetPropertyNumericArrayValue ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING PropertyName, + IN EFI_STRING ConfigureLang, + OUT UINTN *ArraySize + ) +{ + EFI_STATUS Status; + EDKII_REDFISH_VALUE RedfishValue; + EFI_STRING ConfigureLangBuffer; + UINTN BufferSize; + INT64 *IntegerArray; + UINTN Index; + + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName) || ArraySize == NULL) { + return NULL; + } + + *ArraySize = 0; + + // + // Configure Language buffer. + // + BufferSize = sizeof (CHAR16) * MAX_CONF_LANG_LEN; + ConfigureLangBuffer = AllocatePool (BufferSize); + if (ConfigureLangBuffer == NULL) { + DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__)); + return NULL; + } + + UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang, PropertyName); + Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLangBuffer, &RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status)); + return NULL; + } + + if (RedfishValue.Type != REDFISH_VALUE_TYPE_INTEGER_ARRAY) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string array type\n", __FUNCTION__, Schema, Version, ConfigureLang)); + return NULL; + } + + IntegerArray = AllocatePool (sizeof (INT64) * RedfishValue.ArrayCount); + if (IntegerArray == NULL) { + DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__)); + return NULL; + } + + *ArraySize = RedfishValue.ArrayCount; + for (Index = 0; Index < RedfishValue.ArrayCount; Index++) { + IntegerArray[Index] = RedfishValue.Value.IntegerArray[Index]; + } + + return IntegerArray; +} + +/** + + Get the property boolean value in array type. + + @param[in] Schema Schema of this property. + @param[in] Version Schema version. + @param[in] PropertyName Property name. + @param[in] ConfigureLang Configure Language of this property. + @param[out] ArraySize The size of returned array. + + @retval BOOLEAN * Returned boolean array. NULL while error happens. + +**/ +BOOLEAN * +GetPropertyBooleanArrayValue ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING PropertyName, + IN EFI_STRING ConfigureLang, + OUT UINTN *ArraySize + ) +{ + EFI_STATUS Status; + EDKII_REDFISH_VALUE RedfishValue; + EFI_STRING ConfigureLangBuffer; + UINTN BufferSize; + BOOLEAN *BooleanArray; + UINTN Index; + + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName) || ArraySize == NULL) { + return NULL; + } + + *ArraySize = 0; + + // + // Configure Language buffer. + // + BufferSize = sizeof (CHAR16) * MAX_CONF_LANG_LEN; + ConfigureLangBuffer = AllocatePool (BufferSize); + if (ConfigureLangBuffer == NULL) { + DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__)); + return NULL; + } + + UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang, PropertyName); + Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLangBuffer, &RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status)); + return NULL; + } + + if (RedfishValue.Type != REDFISH_VALUE_TYPE_BOOLEAN_ARRAY) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string array type\n", __FUNCTION__, Schema, Version, ConfigureLang)); + return NULL; + } + + BooleanArray = AllocatePool (sizeof (INT64) * RedfishValue.ArrayCount); + if (BooleanArray == NULL) { + DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__)); + return NULL; + } + + *ArraySize = RedfishValue.ArrayCount; + for (Index = 0; Index < RedfishValue.ArrayCount; Index++) { + BooleanArray[Index] = RedfishValue.Value.BooleanArray[Index]; + } + + return BooleanArray; +} + +/** + + Free the list of empty property key values. + + @param[in] EmptyPropKeyValueListHead The head of RedfishCS_EmptyProp_KeyValue + +**/ +VOID +FreeEmptyPropKeyValueList ( + RedfishCS_EmptyProp_KeyValue *EmptyPropKeyValueListHead + ) +{ + RedfishCS_EmptyProp_KeyValue *NextEmptyPropKeyValueList; - if (StrCmp (UnifiedConfigureLangPool[Index2].ConfigureLang, UnifiedConfigureLang) == 0) { - Duplicated = TRUE; - break; - } + while (EmptyPropKeyValueListHead != NULL) { + NextEmptyPropKeyValueList = EmptyPropKeyValueListHead->NextKeyValuePtr; + if (EmptyPropKeyValueListHead->Value->DataValue.CharPtr != NULL) { + FreePool(EmptyPropKeyValueListHead->Value->DataValue.CharPtr); } - - if (Duplicated) { - FreePool (UnifiedConfigureLang); - continue; + if (EmptyPropKeyValueListHead->Value != NULL) { + FreePool(EmptyPropKeyValueListHead->Value); } - - if (UnifiedConfigureLangList->Count >= BIOS_CONFIG_TO_REDFISH_REDPATH_POOL_SIZE) { - FreePool (UnifiedConfigureLang); - Status = EFI_BUFFER_TOO_SMALL; - break; + if (EmptyPropKeyValueListHead->KeyNamePtr != NULL) { + FreePool(EmptyPropKeyValueListHead->KeyNamePtr); } + FreePool (EmptyPropKeyValueListHead); + EmptyPropKeyValueListHead = NextEmptyPropKeyValueList; + }; +} - // - // New configure language. Keep it in Pool - // +/** - UnifiedConfigureLangPool[UnifiedConfigureLangList->Count].ConfigureLang = UnifiedConfigureLang; - UnifiedConfigureLangPool[UnifiedConfigureLangList->Count].Index = ArrayIndex; - ++UnifiedConfigureLangList->Count; - } + Create a new entry of RedfishCS_EmptyProp_KeyValue - FreePool (ConfigureLangList); + @param[in] KeyName The key name. + @param[in] RedfishValue Redfish vale of this key. - // - // Prepare the result to caller. - // - UnifiedConfigureLangList->List = AllocateCopyPool (sizeof (REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG) * UnifiedConfigureLangList->Count, UnifiedConfigureLangPool); +* @retval RedfishCS_EmptyProp_KeyValue Return the new RedfishCS_EmptyProp_KeyValue. +* NULL means no new entry is created. - return Status; +**/ +RedfishCS_EmptyProp_KeyValue * +NewEmptyPropKeyValueFromRedfishValue ( + IN EFI_STRING KeyName, + IN EDKII_REDFISH_VALUE *RedfishValue + ) +{ + RedfishCS_EmptyProp_KeyValue *EmptyPropKeyValue; + RedfishCS_Vague *VagueValue; + RedfishCS_char *KeyNameChar; + VOID *Data; + UINTN DataSize; + INT32 Bool32; + + KeyNameChar = StrUnicodeToAscii(KeyName); + if (KeyNameChar == NULL) { + DEBUG ((DEBUG_ERROR, "%a, Failed to convert unicode to ASCII.\n", __FUNCTION__)); + return NULL; + } + EmptyPropKeyValue = (RedfishCS_EmptyProp_KeyValue *)AllocateZeroPool (sizeof (RedfishCS_EmptyProp_KeyValue)); + if (EmptyPropKeyValue == NULL) { + DEBUG ((DEBUG_ERROR, "%a, Failed to allocate memory for EmptyPropKeyValue\n", __FUNCTION__)); + return NULL; + } + VagueValue = (RedfishCS_Vague *)AllocateZeroPool (sizeof (RedfishCS_Vague)); + if (VagueValue == NULL) { + DEBUG ((DEBUG_ERROR, "%a, Failed to allocate memory for VagueValue\n", __FUNCTION__)); + FreePool (EmptyPropKeyValue); + return NULL; + } + + if (RedfishValue->Type == REDFISH_VALUE_TYPE_BOOLEAN) { + VagueValue->DataType = RedfishCS_Vague_DataType_Bool; + DataSize = sizeof (BOOLEAN); + // + // Redfish JSON to C strcuture converter uses + // "int" for the BOOLEAN. + // + Bool32 = (INT32)RedfishValue->Value.Boolean; + Data = (VOID *)&Bool32; + } else if (RedfishValue->Type == REDFISH_VALUE_TYPE_INTEGER) { + VagueValue->DataType = RedfishCS_Vague_DataType_Int64; + DataSize = sizeof (INT64); + Data = (VOID *)&RedfishValue->Value.Integer; + } else if (RedfishValue->Type == REDFISH_VALUE_TYPE_STRING) { + VagueValue->DataType = RedfishCS_Vague_DataType_String; + DataSize = AsciiStrSize(RedfishValue->Value.Buffer); + Data = (VOID *)RedfishValue->Value.Buffer; + } else { + DEBUG ((DEBUG_ERROR, "%a, wrong type of RedfishValue: %x\n", __FUNCTION__, RedfishValue->Type)); + FreePool (VagueValue); + FreePool (EmptyPropKeyValue); + return NULL; + } + VagueValue->DataValue.CharPtr = (RedfishCS_char *)AllocateCopyPool(DataSize, Data); + EmptyPropKeyValue->Value = VagueValue; + EmptyPropKeyValue->KeyNamePtr = KeyNameChar; + return EmptyPropKeyValue; } /** - Create HTTP payload and send them to redfish service with PATCH method. + Get the property value in the vague type. - @param[in] Service Redfish service. - @param[in] TargetPayload Target payload - @param[in] Json Data in JSON format. - @param[out] Etag Returned ETAG string from Redfish service. + @param[in] Schema Schema of this property. + @param[in] Version Schema version. + @param[in] PropertyName Property name. + @param[in] ConfigureLang Configure Language of this property. + @param[out] NumberOfValues Return the number of vague type of values - @retval EFI_SUCCESS Data is sent to redfish service successfully. - @retval Others Errors occur. + @retval RedfishCS_EmptyProp_KeyValue The pointer to the structure + of vague type of values. **/ -EFI_STATUS -CreatePayloadToPatchResource ( - IN REDFISH_SERVICE *Service, - IN REDFISH_PAYLOAD *TargetPayload, - IN CHAR8 *Json, - OUT CHAR8 **Etag +RedfishCS_EmptyProp_KeyValue * +GetPropertyVagueValue ( + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING PropertyName, + IN EFI_STRING ConfigureLang, + OUT UINT32 *NumberOfValues ) { - REDFISH_PAYLOAD Payload; - EDKII_JSON_VALUE ResourceJsonValue; - REDFISH_RESPONSE PostResponse; - EFI_STATUS Status; - UINTN Index; - EDKII_JSON_VALUE JsonValue; - EDKII_JSON_VALUE OdataIdValue; - CHAR8 *OdataIdString; + EFI_STATUS Status; + RedfishCS_EmptyProp_KeyValue *EmptyPropKeyValueList; + RedfishCS_EmptyProp_KeyValue *PreEmptyPropKeyValueList; + RedfishCS_EmptyProp_KeyValue *FirstEmptyPropKeyValueList; + EDKII_REDFISH_VALUE RedfishValue; + EFI_STRING ConfigureLangBuffer; + EFI_STRING KeyName; + EFI_STRING *ConfigureLangList; + EFI_STRING SearchPattern; + UINTN BufferSize; + UINTN ConfigListCount; + UINTN ConfigListCountIndex; - if (Service == NULL || TargetPayload == NULL || IS_EMPTY_STRING (Json) || Etag == NULL) { - return EFI_INVALID_PARAMETER; + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) { + return NULL; } - ResourceJsonValue = JsonLoadString (Json, 0, NULL); - Payload = RedfishCreatePayload (ResourceJsonValue, Service); - if (Payload == NULL) { - DEBUG ((DEBUG_ERROR, "%a:%d Failed to create JSON payload from JSON value!\n",__FUNCTION__, __LINE__)); - Status = EFI_DEVICE_ERROR; - goto EXIT_FREE_JSON_VALUE; + // + // Configure Language buffer. + // + BufferSize = sizeof (CHAR16) * MAX_CONF_LANG_LEN; + ConfigureLangBuffer = AllocatePool (BufferSize); + if (ConfigureLangBuffer == NULL) { + DEBUG ((DEBUG_ERROR, "%a, Failed to allocate memory for ConfigureLangBuffer\n", __FUNCTION__)); + return NULL; } + UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang, PropertyName); - ZeroMem (&PostResponse, sizeof (REDFISH_RESPONSE)); - Status = RedfishPatchToPayload (TargetPayload, Payload, &PostResponse); + // + // Initial search pattern + // + BufferSize = (StrLen (ConfigureLangBuffer) + StrLen (L"/.*") + 1) * sizeof (CHAR16); // Increase one for the NULL terminator. + SearchPattern = AllocatePool (BufferSize); + if (SearchPattern == NULL) { + DEBUG ((DEBUG_ERROR, "%a, Failed to allocate memory for SearchPattern\n", __FUNCTION__)); + FreePool (ConfigureLangBuffer); + return NULL; + } + BufferSize = BufferSize / sizeof (CHAR16); + StrCpyS (SearchPattern, BufferSize, ConfigureLangBuffer); + StrCatS (SearchPattern, BufferSize, L"/.*"); + Status = RedfishPlatformConfigGetConfigureLang (Schema, Version, SearchPattern, &ConfigureLangList, &ConfigListCount); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a:%d Failed to PATCH payload to Redfish service.\n",__FUNCTION__, __LINE__)); - goto EXIT_FREE_JSON_VALUE; + DEBUG ((DEBUG_ERROR, "%a, %a.%a Get configure language of vague type values of %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status)); + goto ErrorLeave; } - // - // Keep etag. + // Build up the list of RedfishCS_EmptyProp_KeyValue. // - *Etag = NULL; - if (*PostResponse.StatusCode == HTTP_STATUS_200_OK) { - if (PostResponse.HeaderCount != 0) { - for (Index = 0; Index < PostResponse.HeaderCount; Index++) { - if (AsciiStrnCmp (PostResponse.Headers[Index].FieldName, "ETag", 4) == 0) { - *Etag = AllocateCopyPool (AsciiStrSize (PostResponse.Headers[Index].FieldValue), PostResponse.Headers[Index].FieldValue); - } - } - } else if (PostResponse.Payload != NULL) { - // - // No header is returned. Search payload for location. - // - JsonValue = RedfishJsonInPayload (PostResponse.Payload); - if (JsonValue != NULL) { - OdataIdValue = JsonObjectGetValue (JsonValueGetObject (JsonValue), "@odata.etag"); - if (OdataIdValue != NULL) { - OdataIdString = (CHAR8 *)JsonValueGetAsciiString (OdataIdValue); - if (OdataIdString != NULL) { - *Etag = AllocateCopyPool (AsciiStrSize (OdataIdString), OdataIdString); - } - } - } + ConfigListCountIndex = 0; + PreEmptyPropKeyValueList = NULL; + FirstEmptyPropKeyValueList = NULL; + while (ConfigListCountIndex < ConfigListCount) { + Status = RedfishPlatformConfigGetValue(Schema, Version, ConfigureLangList [ConfigListCountIndex], &RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLangList [ConfigListCountIndex], Status)); + goto ErrorLeave; } - } - - RedfishFreeResponse ( - PostResponse.StatusCode, - PostResponse.HeaderCount, - PostResponse.Headers, - PostResponse.Payload - ); + // + // Get the key name. + // + KeyName = GetAttributeNameFromConfigLanguage (ConfigureLangList [ConfigListCountIndex]); + // + // Create an entry of RedfishCS_EmptyProp_KeyValue. + // + EmptyPropKeyValueList = NewEmptyPropKeyValueFromRedfishValue (KeyName, &RedfishValue); + if (EmptyPropKeyValueList == NULL) { + DEBUG ((DEBUG_ERROR, "%a, Failed to create an entry of EmptyPropKeyValueList\n", __FUNCTION__)); + ConfigListCountIndex ++; + continue; + } + // + // Link the RedfishCS_EmptyProp_KeyValue list. + // + if (PreEmptyPropKeyValueList != NULL) { + PreEmptyPropKeyValueList->NextKeyValuePtr = EmptyPropKeyValueList; + } else { + FirstEmptyPropKeyValueList = EmptyPropKeyValueList; + } + PreEmptyPropKeyValueList = EmptyPropKeyValueList; + ConfigListCountIndex ++; + }; + goto LeaveFunction; -EXIT_FREE_JSON_VALUE: - if (Payload != NULL) { - RedfishCleanupPayload (Payload); +ErrorLeave:; + if (FirstEmptyPropKeyValueList != NULL) { + FreeEmptyPropKeyValueList (FirstEmptyPropKeyValueList); } + FirstEmptyPropKeyValueList = NULL; - JsonValueFree (ResourceJsonValue); +LeaveFunction: + if (SearchPattern != NULL) { + FreePool (SearchPattern); + } + if (ConfigureLangBuffer != NULL) { + FreePool (ConfigureLangBuffer); + } + FreePool (ConfigureLangList); - return Status; + *NumberOfValues = (UINT32)ConfigListCount; + return FirstEmptyPropKeyValueList; } /** - Create HTTP payload and send them to redfish service with POST method. + Check and see if we need to do provisioning for this property. - @param[in] Service Redfish service. - @param[in] TargetPayload Target payload - @param[in] Json Data in JSON format. - @param[out] Location Returned location string from Redfish service. - @param[out] Etag Returned ETAG string from Redfish service. + @param[in] PropertyBuffer Pointer to property instance. + @param[in] ProvisionMode TRUE if we are in provision mode. FALSE otherwise. - @retval EFI_SUCCESS Data is sent to redfish service successfully. - @retval Others Errors occur. + @retval TRUE Provision is required. + @retval FALSE Provision is not required. **/ -EFI_STATUS -CreatePayloadToPostResource ( - IN REDFISH_SERVICE *Service, - IN REDFISH_PAYLOAD *TargetPayload, - IN CHAR8 *Json, - OUT CHAR8 **Location, - OUT CHAR8 **Etag +BOOLEAN +PropertyChecker ( + IN VOID *PropertyBuffer, + IN BOOLEAN ProvisionMode ) { - REDFISH_PAYLOAD Payload; - EDKII_JSON_VALUE ResourceJsonValue; - REDFISH_RESPONSE PostResponse; - EFI_STATUS Status; - UINTN Index; - EDKII_JSON_VALUE JsonValue; - EDKII_JSON_VALUE OdataIdValue; - CHAR8 *OdataIdString; + if (ProvisionMode) { + return TRUE; + } - if (Service == NULL || TargetPayload == NULL || IS_EMPTY_STRING (Json) || Location == NULL || Etag == NULL) { - return EFI_INVALID_PARAMETER; + if (!ProvisionMode && PropertyBuffer != NULL) { + return TRUE; } - ResourceJsonValue = JsonLoadString (Json, 0, NULL); - Payload = RedfishCreatePayload (ResourceJsonValue, Service); - if (Payload == NULL) { - DEBUG ((DEBUG_ERROR, "%a:%d Failed to create JSON payload from JSON value!\n",__FUNCTION__, __LINE__)); - Status = EFI_DEVICE_ERROR; - goto EXIT_FREE_JSON_VALUE; + return FALSE; +} + +/** + + Check and see if ETAG is identical to what we keep in system. + + @param[in] Uri URI requested + @param[in] EtagInHeader ETAG string returned from HTTP request. + @param[in] EtagInJson ETAG string in JSON body. + + @retval TRUE ETAG is identical. + @retval FALSE ETAG is changed. + +**/ +BOOLEAN +CheckEtag ( + IN EFI_STRING Uri, + IN CHAR8 *EtagInHeader, + IN CHAR8 *EtagInJson + ) +{ + CHAR8 *EtagInDb; + + if (IS_EMPTY_STRING (Uri)) { + return FALSE; } - ZeroMem (&PostResponse, sizeof (REDFISH_RESPONSE)); - Status = RedfishPostToPayload (TargetPayload, Payload, &PostResponse); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a:%d Failed to POST Attribute Registry to Redfish service.\n",__FUNCTION__, __LINE__)); - goto EXIT_FREE_JSON_VALUE; + if (IS_EMPTY_STRING (EtagInHeader) && IS_EMPTY_STRING (EtagInJson)) { + return FALSE; } // - // per Redfish spec. the URL of new eresource will be returned in "Location" header. + // Check ETAG to see if we need to consume it // - *Location = NULL; - *Etag = NULL; - if (*PostResponse.StatusCode == HTTP_STATUS_200_OK) { - if (PostResponse.HeaderCount != 0) { - for (Index = 0; Index < PostResponse.HeaderCount; Index++) { - if (AsciiStrnCmp (PostResponse.Headers[Index].FieldName, "Location", 8) == 0) { - *Location = AllocateCopyPool (AsciiStrSize (PostResponse.Headers[Index].FieldValue), PostResponse.Headers[Index].FieldValue); - } else if (AsciiStrnCmp (PostResponse.Headers[Index].FieldName, "ETag", 4) == 0) { - *Etag = AllocateCopyPool (AsciiStrSize (PostResponse.Headers[Index].FieldValue), PostResponse.Headers[Index].FieldValue); - } - } - } else if (PostResponse.Payload != NULL) { - // - // No header is returned. Search payload for location. - // - JsonValue = RedfishJsonInPayload (PostResponse.Payload); - if (JsonValue != NULL) { - OdataIdValue = JsonObjectGetValue (JsonValueGetObject (JsonValue), "@odata.id"); - if (OdataIdValue != NULL) { - OdataIdString = (CHAR8 *)JsonValueGetAsciiString (OdataIdValue); - if (OdataIdString != NULL) { - *Location = AllocateCopyPool (AsciiStrSize (OdataIdString), OdataIdString); - } - } + EtagInDb = NULL; + EtagInDb = GetEtagWithUri (Uri); + if (EtagInDb == NULL) { + DEBUG ((REDFISH_DEBUG_TRACE, "%a, no ETAG record cound be found for: %s\n", __FUNCTION__, Uri)); + return FALSE; + } - OdataIdValue = JsonObjectGetValue (JsonValueGetObject (JsonValue), "@odata.etag"); - if (OdataIdValue != NULL) { - OdataIdString = (CHAR8 *)JsonValueGetAsciiString (OdataIdValue); - if (OdataIdString != NULL) { - *Etag = AllocateCopyPool (AsciiStrSize (OdataIdString), OdataIdString); - } - } - } + if (EtagInHeader != NULL) { + if (AsciiStrCmp (EtagInDb, EtagInHeader) == 0) { + FreePool (EtagInDb); + return TRUE; } } - // - // This is not expected as service does not follow spec. - // - if (*Location == NULL) { - Status = EFI_DEVICE_ERROR; + if (EtagInJson != NULL) { + if (AsciiStrCmp (EtagInDb, EtagInJson) == 0) { + FreePool (EtagInDb); + return TRUE; + } } - RedfishFreeResponse ( - PostResponse.StatusCode, - PostResponse.HeaderCount, - PostResponse.Headers, - PostResponse.Payload - ); - - RedfishCleanupPayload (Payload); - -EXIT_FREE_JSON_VALUE: - JsonValueFree (JsonValue); - JsonValueFree (ResourceJsonValue); + FreePool (EtagInDb); - return Status; + return FALSE; } /** + Check and see if given ObjectName can be found in JsonObj or not - Find Redfish Resource Config Protocol that supports given schema and version. + @param[in] JsonObj JSON object to search + @param[in] ObjectName Object name - @param[in] Schema Schema name. - @param[in] Major Schema version major number. - @param[in] Minor Schema version minor number. - @param[in] Errata Schema version errata number. - - @retval EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL * Pointer to protocol - @retval NULL No protocol found. + @retval EDKII_JSON_VALUE * Pointer to Json object is found. NULL otherwise. **/ -EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL * -GetRedfishResourceConfigProtocol ( - IN CHAR8 *Schema, - IN CHAR8 *Major, - IN CHAR8 *Minor, - IN CHAR8 *Errata +EDKII_JSON_VALUE * +MatchJsonObject ( + IN EDKII_JSON_VALUE *JsonObj, + IN CHAR8 *ObjectName ) { - EFI_STATUS Status; - EFI_HANDLE *HandleBuffer; - UINTN NumberOfHandles; - UINTN Index; - EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL *Protocol; - REDFISH_SCHEMA_INFO SchemaInfo; - BOOLEAN Found; + EDKII_JSON_VALUE N; + CHAR8 *Key; + EDKII_JSON_VALUE Value; - if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Major) || IS_EMPTY_STRING (Minor) || IS_EMPTY_STRING (Errata)) { + if (JsonObj == NULL || IS_EMPTY_STRING (ObjectName)) { return NULL; } - Status = gBS->LocateHandleBuffer ( - ByProtocol, - &gEdkIIRedfishResourceConfigProtocolGuid, - NULL, - &NumberOfHandles, - &HandleBuffer - ); - if (EFI_ERROR (Status)) { + if (!JsonValueIsObject (JsonObj)) { return NULL; } - Found = FALSE; - - for (Index = 0; Index < NumberOfHandles; Index++) { - Status = gBS->HandleProtocol ( - HandleBuffer[Index], - &gEdkIIRedfishResourceConfigProtocolGuid, - (VOID **) &Protocol - ); - if (EFI_ERROR (Status)) { - continue; - } - - Status = Protocol->GetInfo (Protocol, &SchemaInfo); - if (EFI_ERROR (Status)) { - continue; + EDKII_JSON_OBJECT_FOREACH_SAFE (JsonObj, N, Key, Value) { + if (AsciiStrCmp (Key, ObjectName) == 0) { + return Value; } - - if (AsciiStrCmp (Schema, SchemaInfo.Schema) == 0 && - AsciiStrCmp (Major, SchemaInfo.Major) == 0 && - AsciiStrCmp (Minor, SchemaInfo.Minor) == 0 && - AsciiStrCmp (Errata, SchemaInfo.Errata) == 0) { - Found = TRUE; - break; - } } - FreePool (HandleBuffer); - - return (Found ? Protocol : NULL); + return NULL; } /** - Get supported schema list by given specify schema name. + Check and see if given property is in JSON context or not - @param[in] Schema Schema type name. - @param[out] SchemaInfo Returned schema information. + @param[in] Property Property name string + @param[in] Json The JSON context to search. - @retval EFI_SUCCESS Schema information is returned successfully. - @retval Others Errors occur. + @retval TRUE Property is found in JSON context + @retval FALSE Property is not in JSON context **/ -EFI_STATUS -GetSupportedSchemaVersion ( - IN CHAR8 *Schema, - OUT REDFISH_SCHEMA_INFO *SchemaInfo +BOOLEAN +MatchPropertyWithJsonContext ( + IN EFI_STRING Property, + IN CHAR8 *Json ) { - EFI_STATUS Status; - CHAR8 *SupportSchema; - CHAR8 *SchemaName; - UINTN Index; - UINTN Index2; - BOOLEAN Found; + CHAR8 *AsciiProperty; + CHAR8 *PropertyNode; + UINTN Index; + EDKII_JSON_VALUE *JsonObj; + EDKII_JSON_VALUE *MatchObj; + EDKII_JSON_TYPE JsonType; - if (IS_EMPTY_STRING (Schema) || SchemaInfo == NULL) { - return EFI_INVALID_PARAMETER; + if (IS_EMPTY_STRING (Property) || IS_EMPTY_STRING (Json)) { + return FALSE; } - Status = RedfishPlatformConfigGetSupportedSchema (NULL, &SupportSchema); - if (EFI_ERROR (Status)) { - return Status; + JsonObj = JsonLoadString (Json, 0, NULL); + if (JsonObj == NULL || !JsonValueIsObject (JsonObj)) { + return FALSE; } - DEBUG ((DEBUG_INFO, "Supported schema: %a\n", SupportSchema)); - - Index = 0; - Found = FALSE; - SchemaName = SupportSchema; - while (TRUE) { - - if (SupportSchema[Index] == ';' || SupportSchema[Index] == '\0') { - if (AsciiStrnCmp (&SchemaName[SCHEMA_NAME_PREFIX_OFFSET], Schema, AsciiStrLen (Schema)) == 0) { - Found = TRUE; - SupportSchema[Index] = '\0'; - break; - } - - SchemaName = &SupportSchema[Index + 1]; - } - - if (SupportSchema[Index] == '\0') { - break; - } - - ++Index; + AsciiProperty = StrUnicodeToAscii (Property); + if (AsciiProperty == NULL) { + return FALSE; } - if (Found) { - - AsciiStrCpyS (SchemaInfo->Schema, REDFISH_SCHEMA_STRING_SIZE, Schema); - - // - // forward to '.' - // - Index = 0; - while (SchemaName[Index] != '\0' && SchemaName[Index] != '.') { - ++Index; - } - ASSERT (SchemaName[Index] != '\0'); + Index = 0; + PropertyNode = AsciiProperty; + MatchObj = JsonObj; - // - // Skip '.' and 'v' - // - Index += 2; + // + // Walk through property and find corresponding object in JSON input + // + while (AsciiProperty[Index] != '\0') { - // - // forward to '_' - // - Index2 = Index; - while (SchemaName[Index2] != '\0' && SchemaName[Index2] != '_') { - ++Index2; + if (AsciiProperty[Index] == '/') { + AsciiProperty[Index] = '\0'; + MatchObj = MatchJsonObject (MatchObj, PropertyNode); + if (MatchObj == NULL) { + PropertyNode = NULL; + break; + } + + PropertyNode = &AsciiProperty[Index + 1]; } - ASSERT (SchemaName[Index2] != '\0'); - AsciiStrnCpyS (SchemaInfo->Major, REDFISH_SCHEMA_VERSION_SIZE, &SchemaName[Index], (Index2 - Index)); - Index = Index2; + Index++; + } - // - // Skip '_' - // - ++Index; + if (PropertyNode != NULL) { + MatchObj = MatchJsonObject (MatchObj, PropertyNode); + } + // + // Value check + // + if (MatchObj != NULL) { // - // forward to '_' + // If object has empty value, treat it as not matching // - Index2 = Index; - while (SchemaName[Index2] != '\0' && SchemaName[Index2] != '_') { - ++Index2; + JsonType = JsonGetType (MatchObj); + switch (JsonType) { + case EdkiiJsonTypeObject: + if (JsonValueIsNull (MatchObj)) { + MatchObj = NULL; + } + break; + case EdkiiJsonTypeArray: + if (JsonArrayCount (MatchObj) == 0) { + MatchObj = NULL; + } + break; + case EdkiiJsonTypeString: + if (IS_EMPTY_STRING (JsonValueGetString (MatchObj))) { + MatchObj = NULL; + } + break; + case EdkiiJsonTypeNull: + MatchObj = NULL; + break; + default: + break; } - ASSERT (SchemaName[Index2] != '\0'); - - AsciiStrnCpyS (SchemaInfo->Minor, REDFISH_SCHEMA_VERSION_SIZE, &SchemaName[Index], (Index2 - Index)); - Index = Index2; - - // - // Skip '_' - // - ++Index; - - AsciiStrCpyS (SchemaInfo->Errata, REDFISH_SCHEMA_VERSION_SIZE, &SchemaName[Index]); } - FreePool (SupportSchema); - - return (Found ? EFI_SUCCESS : EFI_NOT_FOUND); -} - -/** - - Return system root path. This is dummy function now. + FreePool (AsciiProperty); - @retval NULL Can not find system root path. - @retval Other System root path is returned. - -**/ -CHAR8 * -RedfishGetSystemRootPath ( - VOID - ) -{ - return AllocateCopyPool (AsciiStrSize (REDFISH_SYSTEM_ROOT_PATH), REDFISH_SYSTEM_ROOT_PATH); + return (MatchObj == NULL ? FALSE : TRUE); } /** - Get schema information by given protocol and service instance. + Create string array and append to arry node in Redfish JSON convert format. - @param[in] RedfishService Pointer to Redfish service instance. - @param[in] JsonStructProtocol Json Structure protocol instance. - @param[in] Uri Target URI. - @param[out] SchemaInfo Returned schema information. + @param[in,out] Head The head of string array. + @param[in] StringArray Input string array. + @param[in] ArraySize The size of StringArray. - @retval EFI_SUCCESS Schema information is returned successfully. - @retval Others Errors occur. + @retval EFI_SUCCESS String array is created successfully. + @retval Others Error happens **/ EFI_STATUS -GetRedfishSchemaInfo ( - IN REDFISH_SERVICE *RedfishService, - IN EFI_REST_JSON_STRUCTURE_PROTOCOL *JsonStructProtocol, - IN CHAR8 *Uri, - OUT REDFISH_SCHEMA_INFO *SchemaInfo +AddRedfishCharArray ( + IN OUT RedfishCS_char_Array **Head, + IN CHAR8 **StringArray, + IN UINTN ArraySize ) { - EFI_STATUS Status; - REDFISH_RESPONSE Response; - REDFISH_PAYLOAD Payload; - CHAR8 *JsonText; - EFI_REST_JSON_STRUCTURE_HEADER *Header; + UINTN Index; + RedfishCS_char_Array *CharArrayBuffer; + RedfishCS_char_Array *PreArrayBuffer; - if (RedfishService == NULL || JsonStructProtocol == NULL || IS_EMPTY_STRING (Uri) || SchemaInfo == NULL) { + if (Head == NULL || StringArray == NULL || ArraySize == 0) { return EFI_INVALID_PARAMETER; } - Status = GetResourceByPath (RedfishService, Uri, &Response); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a, failed to get resource from %a %r", __FUNCTION__, Uri, Status)); - return Status; - } - - Payload = Response.Payload; - ASSERT (Payload != NULL); + PreArrayBuffer = NULL; + for (Index = 0; Index < ArraySize; Index++) { + CharArrayBuffer = AllocatePool (sizeof (RedfishCS_char_Array)); + if (CharArrayBuffer == NULL) { + ASSERT (CharArrayBuffer != NULL); + continue; + } - JsonText = JsonDumpString (RedfishJsonInPayload (Payload), EDKII_JSON_COMPACT); - ASSERT (JsonText != NULL); + if (Index == 0) { + *Head = CharArrayBuffer; + } - // - // Convert JSON text to C structure. - // - Status = JsonStructProtocol->ToStructure ( - JsonStructProtocol, - NULL, - JsonText, - &Header - ); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a, ToStructure() failed: %r\n", __FUNCTION__, Status)); - return Status; + CharArrayBuffer->ArrayValue = StringArray[Index]; + CharArrayBuffer->Next = NULL; + if (PreArrayBuffer != NULL) { + PreArrayBuffer->Next = CharArrayBuffer; + } + PreArrayBuffer = CharArrayBuffer; } - AsciiStrCpyS (SchemaInfo->Schema, REDFISH_SCHEMA_STRING_SIZE, Header->JsonRsrcIdentifier.NameSpace.ResourceTypeName); - AsciiStrCpyS (SchemaInfo->Major, REDFISH_SCHEMA_VERSION_SIZE, Header->JsonRsrcIdentifier.NameSpace.MajorVersion); - AsciiStrCpyS (SchemaInfo->Minor, REDFISH_SCHEMA_VERSION_SIZE, Header->JsonRsrcIdentifier.NameSpace.MinorVersion); - AsciiStrCpyS (SchemaInfo->Errata, REDFISH_SCHEMA_VERSION_SIZE, Header->JsonRsrcIdentifier.NameSpace.ErrataVersion); - - // - // Release resource. - // - JsonStructProtocol->DestoryStructure (JsonStructProtocol, Header); - FreePool (JsonText); - RedfishFreeResponse (Response.StatusCode, Response.HeaderCount, Response.Headers, Response.Payload); - return EFI_SUCCESS; } /** - Get the property name by given Configure Langauge. + Create numeric array and append to arry node in Redfish JSON convert format. - @param[in] ConfigureLang Configure Language string. + @param[in,out] Head The head of string array. + @param[in] NumericArray Input numeric array. + @param[in] ArraySize The size of NumericArray. - @retval EFI_STRING Pointer to property name. - @retval NULL There is error. + @retval EFI_SUCCESS String array is created successfully. + @retval Others Error happens **/ -EFI_STRING -GetPropertyFromConfigureLang ( - IN EFI_STRING ConfigureLang +EFI_STATUS +AddRedfishNumericArray ( + IN OUT RedfishCS_int64_Array **Head, + IN INT64 *NumericArray, + IN UINTN ArraySize ) { - EFI_STRING Property; - UINTN Index; + UINTN Index; + RedfishCS_int64_Array *NumericArrayBuffer; + RedfishCS_int64_Array *PreArrayBuffer; - if (ConfigureLang == NULL) { - return NULL; + if (Head == NULL || NumericArray == NULL || ArraySize == 0) { + return EFI_INVALID_PARAMETER; } - Index = 0; - Property = ConfigureLang; - - while (ConfigureLang[Index] != '\0') { - if (ConfigureLang[Index] == L'/') { - Property = &ConfigureLang[Index]; + PreArrayBuffer = NULL; + for (Index = 0; Index < ArraySize; Index++) { + NumericArrayBuffer = AllocatePool (sizeof (RedfishCS_int64_Array)); + if (NumericArrayBuffer == NULL) { + ASSERT (NumericArrayBuffer != NULL); + continue; } - ++Index; + if (Index == 0) { + *Head = NumericArrayBuffer; + } + NumericArrayBuffer->ArrayValue = AllocatePool (sizeof (RedfishCS_int64)); + if (NumericArrayBuffer->ArrayValue == NULL) { + ASSERT (NumericArrayBuffer->ArrayValue != NULL); + continue; + } + *NumericArrayBuffer->ArrayValue = NumericArray[Index]; + NumericArrayBuffer->Next = NULL; + if (PreArrayBuffer != NULL) { + PreArrayBuffer->Next = NumericArrayBuffer; + } + PreArrayBuffer = NumericArrayBuffer; } - ++Property; - - return Property; + return EFI_SUCCESS; } /** - Get the property value in string type. + Create boolean array and append to arry node in Redfish JSON convert format. - @param[in] Schema Schema of this property. - @param[in] Version Schema version. - @param[in] PropertyName Property name. - @param[in] ConfigureLang Configure Language of this property. + @param[in,out] Head The head of string array. + @param[in] BooleanArray Input boolean array. + @param[in] ArraySize The size of BooleanArray. - @retval CHAR8* Pointer to the CHAR8 buffer. - @retval NULL There is error. + @retval EFI_SUCCESS String array is created successfully. + @retval Others Error happens **/ -CHAR8 * -GetPropertyStringValue ( - IN CHAR8 *Schema, - IN CHAR8 *Version, - IN EFI_STRING PropertyName, - IN EFI_STRING ConfigureLang +EFI_STATUS +AddRedfishBooleanArray ( + IN OUT RedfishCS_bool_Array **Head, + IN BOOLEAN *BooleanArray, + IN UINTN ArraySize ) { - EFI_STATUS Status; - EDKII_REDFISH_VALUE RedfishValue; - EFI_STRING ConfigureLangBuffer; - UINTN BufferSize; - CHAR8 *AsciiStringValue; + UINTN Index; + RedfishCS_bool_Array *BooleanArrayBuffer; + RedfishCS_bool_Array *PreArrayBuffer; - if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) { - return NULL; + if (Head == NULL || BooleanArrayBuffer == NULL || ArraySize == 0) { + return EFI_INVALID_PARAMETER; } - // - // Configure Language buffer. - // - BufferSize = sizeof (CHAR16) * MAX_CONF_LANG_LEN; - ConfigureLangBuffer = AllocatePool (BufferSize); - if (ConfigureLangBuffer == NULL) { - return NULL; - } + PreArrayBuffer = NULL; + for (Index = 0; Index < ArraySize; Index++) { + BooleanArrayBuffer = AllocatePool (sizeof (RedfishCS_bool_Array)); + if (BooleanArrayBuffer == NULL) { + ASSERT (BooleanArrayBuffer != NULL); + continue; + } - UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang, PropertyName); - Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLangBuffer, &RedfishValue); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status)); - return NULL; - } + if (Index == 0) { + *Head = BooleanArrayBuffer; + } - if (RedfishValue.Type != REDFISH_VALUE_TYPE_STRING) { - DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string type\n", __FUNCTION__, Schema, Version, ConfigureLang)); - return NULL; + BooleanArrayBuffer->ArrayValue = AllocatePool (sizeof (RedfishCS_bool)); + if (BooleanArrayBuffer->ArrayValue == NULL) { + ASSERT (BooleanArrayBuffer->ArrayValue != NULL); + continue; + } + *BooleanArrayBuffer->ArrayValue = BooleanArray[Index]; + BooleanArrayBuffer->Next = NULL; + if (PreArrayBuffer != NULL) { + PreArrayBuffer->Next = BooleanArrayBuffer; + } + PreArrayBuffer = BooleanArrayBuffer; } - AsciiStringValue = AllocateCopyPool (AsciiStrSize (RedfishValue.Value.Buffer), RedfishValue.Value.Buffer); - ASSERT (AsciiStringValue != NULL); - - return AsciiStringValue; + return EFI_SUCCESS; } /** - Get the property value in numeric type. + Check and see if value in Redfish string array are all the same as the one + from HII configuration. - @param[in] Schema Schema of this property. - @param[in] Version Schema version. - @param[in] PropertyName Property name. - @param[in] ConfigureLang Configure Language of this property. + @param[in] Head The head of string array. + @param[in] StringArray Input string array. + @param[in] ArraySize The size of StringArray. - @retval INT64* Pointer to the INT64 value. - @retval NULL There is error. + @retval TRUE All string in Redfish array are as same as string + in HII configuration array. + FALSE These two array are not identical. **/ -INT64 * -GetPropertyNumericValue ( - IN CHAR8 *Schema, - IN CHAR8 *Version, - IN EFI_STRING PropertyName, - IN EFI_STRING ConfigureLang +BOOLEAN +CompareRedfishStringArrayValues ( + IN RedfishCS_char_Array *Head, + IN CHAR8 **StringArray, + IN UINTN ArraySize ) { - EFI_STATUS Status; - EDKII_REDFISH_VALUE RedfishValue; - EFI_STRING ConfigureLangBuffer; - UINTN BufferSize; - INT64 *ResultValue; + UINTN Index; + RedfishCS_char_Array *CharArrayBuffer; - if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) { - return NULL; + if (Head == NULL || StringArray == NULL || ArraySize == 0) { + return FALSE; } - // - // Configure Language buffer. - // - BufferSize = sizeof (CHAR16) * MAX_CONF_LANG_LEN; - ConfigureLangBuffer = AllocatePool (BufferSize); - if (ConfigureLangBuffer == NULL) { - return NULL; - } + CharArrayBuffer = Head; + Index = 0; + while (CharArrayBuffer != NULL && Index < ArraySize) { - UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang, PropertyName); - Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLangBuffer, &RedfishValue); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status)); - return NULL; - } + if (AsciiStrCmp (StringArray[Index], CharArrayBuffer->ArrayValue) != 0) { + break; + } - if (RedfishValue.Type != REDFISH_VALUE_TYPE_INTEGER) { - DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not numeric type\n", __FUNCTION__, Schema, Version, ConfigureLang)); - return NULL; + Index++; + CharArrayBuffer = CharArrayBuffer->Next; } - ResultValue = AllocatePool (sizeof (INT64)); - ASSERT (ResultValue != NULL); - if (ResultValue == NULL) { - return NULL; + if (CharArrayBuffer != NULL || Index < ArraySize) { + return FALSE; } - *ResultValue = RedfishValue.Value.Integer; - - return ResultValue; + return TRUE; } /** - Get the property value in Boolean type. + Check and see if value in Redfish numeric array are all the same as the one + from HII configuration. - @param[in] Schema Schema of this property. - @param[in] Version Schema version. - @param[in] PropertyName Property name. - @param[in] ConfigureLang Configure Language of this property. + @param[in] Head The head of Redfish CS numeraic array. + @param[in] NumericArray Input numeric array. + @param[in] ArraySize The size of NumericArray. - @retval BOOLEAN Boolean value returned by this property. + @retval TRUE All string in Redfish array are as same as integer + in HII configuration array. + FALSE These two array are not identical. **/ -BOOLEAN * -GetPropertyBooleanValue ( - IN CHAR8 *Schema, - IN CHAR8 *Version, - IN EFI_STRING PropertyName, - IN EFI_STRING ConfigureLang +BOOLEAN +CompareRedfishNumericArrayValues ( + IN RedfishCS_int64_Array *Head, + IN INT64 *NumericArray, + IN UINTN ArraySize ) { - EFI_STATUS Status; - EDKII_REDFISH_VALUE RedfishValue; - EFI_STRING ConfigureLangBuffer; - UINTN BufferSize; - BOOLEAN *ResultValue; - - if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) { - return NULL; - } + UINTN Index; + RedfishCS_int64_Array *NumericArrayBuffer; - // - // Configure Language buffer. - // - BufferSize = sizeof (CHAR16) * MAX_CONF_LANG_LEN; - ConfigureLangBuffer = AllocatePool (BufferSize); - if (ConfigureLangBuffer == NULL) { - return NULL; + if (Head == NULL || NumericArray == NULL || ArraySize == 0) { + return FALSE; } - UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang, PropertyName); - Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLangBuffer, &RedfishValue); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status)); - return NULL; - } + NumericArrayBuffer = Head; + Index = 0; + while (NumericArrayBuffer != NULL && Index < ArraySize) { + if (NumericArray[Index] != *NumericArrayBuffer->ArrayValue) { + break; + } - if (RedfishValue.Type != REDFISH_VALUE_TYPE_BOOLEAN) { - DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not boolean type\n", __FUNCTION__, Schema, Version, ConfigureLang)); - return NULL; + Index++; + NumericArrayBuffer = NumericArrayBuffer->Next; } - ResultValue = AllocatePool (sizeof (BOOLEAN)); - ASSERT (ResultValue != NULL); - if (ResultValue == NULL) { - return NULL; + if (NumericArrayBuffer != NULL || Index < ArraySize) { + return FALSE; } - *ResultValue = RedfishValue.Value.Boolean; - - return ResultValue; + return TRUE; } /** - Check and see if we need to do provisioning for this property. + Check and see if value in Redfish boolean array are all the same as the one + from HII configuration. - @param[in] PropertyBuffer Pointer to property instance. - @param[in] ProvisionMode TRUE if we are in provision mode. FALSE otherwise. + @param[in] Head The head of Redfish CS boolean array. + @param[in] BooleanArray Input boolean array. + @param[in] ArraySize The size of BooleanArray. - @retval TRUE Provision is required. - @retval FALSE Provision is not required. + @retval TRUE All string in Redfish array are as same as integer + in HII configuration array. + FALSE These two array are not identical. **/ BOOLEAN -PropertyChecker ( - IN VOID *PropertyBuffer, - IN BOOLEAN ProvisionMode +CompareRedfishBooleanArrayValues ( + IN RedfishCS_bool_Array *Head, + IN BOOLEAN *BooleanArray, + IN UINTN ArraySize ) { - if (ProvisionMode && PropertyBuffer == NULL) { - return TRUE; + UINTN Index; + RedfishCS_bool_Array *BooleanArrayBuffer; + + if (Head == NULL || BooleanArray == NULL || ArraySize == 0) { + return FALSE; } - if (!ProvisionMode && PropertyBuffer != NULL) { - return TRUE; + BooleanArrayBuffer = Head; + Index = 0; + while (BooleanArrayBuffer != NULL && Index < ArraySize) { + if (BooleanArray[Index] != *BooleanArrayBuffer->ArrayValue) { + break; + } + + Index++; + BooleanArrayBuffer = BooleanArrayBuffer->Next; } - return FALSE; + if (BooleanArrayBuffer != NULL || Index < ArraySize) { + return FALSE; + } + + return TRUE; } /** - Check and see if we need to do provisioning for this two properties. + Check and see if any difference between two vague value set. + This is just a simple check. - @param[in] PropertyBuffer1 Pointer to property instance 1. - @param[in] PropertyBuffer2 Pointer to property instance 2. - @param[in] ProvisionMode TRUE if we are in provision mode. FALSE otherwise. + @param[in] RedfishVagueKeyValuePtr The vague key value sets on Redfish service. + @param[in] RedfishVagueKeyValueNumber The numebr of vague key value sets + @param[in] ConfigVagueKeyValuePtr The vague configuration on platform. + @param[in] ConfigVagueKeyValueNumber The numebr of vague key value sets - @retval TRUE Provision is required. - @retval FALSE Provision is not required. + @retval TRUE All values are the same. + FALSE There is some difference. **/ BOOLEAN -PropertyChecker2Parm ( - IN VOID *PropertyBuffer1, - IN VOID *PropertyBuffer2, - IN BOOLEAN ProvisionMode +CompareRedfishPropertyVagueValues ( + IN RedfishCS_EmptyProp_KeyValue *RedfishVagueKeyValuePtr, + IN UINT32 RedfishVagueKeyValueNumber, + IN RedfishCS_EmptyProp_KeyValue *ConfigVagueKeyValuePtr, + IN UINT32 ConfigVagueKeyValueNumber ) -{ - if (ProvisionMode && (PropertyBuffer1 == NULL || PropertyBuffer2 == NULL)) { - return TRUE; - } + { + RedfishCS_EmptyProp_KeyValue *ThisConfigVagueKeyValuePtr; + RedfishCS_EmptyProp_KeyValue *ThisRedfishVagueKeyValuePtr; - if (!ProvisionMode && PropertyBuffer1 != NULL && PropertyBuffer2 != NULL) { - return TRUE; + if (RedfishVagueKeyValueNumber != ConfigVagueKeyValueNumber) { + return FALSE; } - return FALSE; + ThisConfigVagueKeyValuePtr = ConfigVagueKeyValuePtr; + // + // Loop through all key/value on system. + // + while (ThisConfigVagueKeyValuePtr != NULL) { + ThisRedfishVagueKeyValuePtr = RedfishVagueKeyValuePtr; + // + // Loop through all key/value on Redfish service.. + // + while (ThisRedfishVagueKeyValuePtr != NULL) { + if (AsciiStrCmp(ThisConfigVagueKeyValuePtr->KeyNamePtr, ThisRedfishVagueKeyValuePtr->KeyNamePtr) == 0) { + // + // Check the type of value. + // + if (ThisConfigVagueKeyValuePtr->Value->DataType != ThisRedfishVagueKeyValuePtr->Value->DataType) { + return FALSE; + } + // + // Check the value. + // + if (ThisConfigVagueKeyValuePtr->Value->DataType == RedfishCS_Vague_DataType_String) { + // + // Is the string identical? + // + if (AsciiStrCmp (ThisConfigVagueKeyValuePtr->Value->DataValue.CharPtr, + ThisRedfishVagueKeyValuePtr->Value->DataValue.CharPtr + ) == 0) { + break; + } else{ + return FALSE; + } + } else if (ThisConfigVagueKeyValuePtr->Value->DataType == RedfishCS_Vague_DataType_Int64) { + if (*ThisConfigVagueKeyValuePtr->Value->DataValue.Int64Ptr == *ThisRedfishVagueKeyValuePtr->Value->DataValue.Int64Ptr) { + break; + } else { + return FALSE; + } + } else if (ThisConfigVagueKeyValuePtr->Value->DataType == RedfishCS_Vague_DataType_Bool) { + if ((UINT8)*ThisConfigVagueKeyValuePtr->Value->DataValue.BoolPtr == (UINT8)*ThisRedfishVagueKeyValuePtr->Value->DataValue.BoolPtr) { + break; + } else { + return FALSE; + } + } else { + return FALSE; + } + } + ThisRedfishVagueKeyValuePtr = ThisRedfishVagueKeyValuePtr->NextKeyValuePtr; + }; + if (ThisRedfishVagueKeyValuePtr == NULL) { + // + // No matched key name. Threat these two vague value set is different. + // + return FALSE; + } + ThisConfigVagueKeyValuePtr = ThisConfigVagueKeyValuePtr->NextKeyValuePtr; + }; + return TRUE; } /** diff --git a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.inf b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.inf index f9f283fdcc..84f338e680 100644 --- a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.inf +++ b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.inf @@ -1,6 +1,6 @@ ## @file # -# (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP
+# (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -27,6 +27,7 @@ [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec + NetworkPkg/NetworkPkg.dec RedfishPkg/RedfishPkg.dec RedfishClientPkg/RedfishClientPkg.dec @@ -35,16 +36,25 @@ BaseMemoryLib DebugLib MemoryAllocationLib - PrintLib RedfishLib RedfishPlatformConfigLib UefiLib UefiBootServicesTableLib UefiRuntimeServicesTableLib + PrintLib + HttpLib [Protocols] - gEdkIIRedfishETagProtocolGuid ## CONSUMED ## + gEdkIIRedfishETagProtocolGuid ## CONSUMED ## + gEdkIIRedfishConfigLangMapProtocolGuid ## CONSUMED ## [Pcd] - gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaStringSize - gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaVersionSize + +[Guids] + +[BuildOptions] + # + # NOTE: /wd4706 disables the following Visual Studio compiler warning in Jansson: + # "C4706: assignment within conditional expression" + # + MSFT:*_*_*_CC_FLAGS = /wd4706 -- 2.32.0.windows.2