From 10dc8c561c687c9e73e29743d04d828cca56a288 Mon Sep 17 00:00:00 2001 From: Abner Chang Date: Fri, 16 Oct 2020 16:24:04 +0800 Subject: [PATCH] RedfishPkg/RedfishRestExDxe: Implementation of EFI REST EX Protocol BZ#: 2908 https://bugzilla.tianocore.org/show_bug.cgi?id=2908 Implementation of EFI EX Protocol according to UEFI spec 2.8 Section 29.7.2 EFI REST EX Protocol. This is the network stack based EFI REST EX protocol instance. Signed-off-by: Jiaxin Wu Signed-off-by: Siyuan Fu Signed-off-by: Fan Wang Signed-off-by: Ting Ye Signed-off-by: Abner Chang Cc: Jiaxin Wu Cc: Siyuan Fu Cc: Fan Wang Cc: Jiewen Yao Cc: Nickle Wang Cc: Peter O'Hanley Reviewed-by: Nickle Wang --- RedfishPkg/Redfish.fdf.inc | 1 + RedfishPkg/RedfishComponents.dsc.inc | 1 + RedfishPkg/RedfishPkg.dsc | 4 + RedfishPkg/RedfishRestExDxe/ComponentName.c | 222 +++++ .../RedfishRestExDxe/RedfishRestExDriver.c | 831 ++++++++++++++++++ .../RedfishRestExDxe/RedfishRestExDriver.h | 650 ++++++++++++++ .../RedfishRestExDxe/RedfishRestExDxe.inf | 63 ++ .../RedfishRestExDxe/RedfishRestExDxe.uni | 16 + .../RedfishRestExDxeExtra.uni | 15 + .../RedfishRestExDxe/RedfishRestExImpl.c | 157 ++++ .../RedfishRestExDxe/RedfishRestExInternal.h | 611 +++++++++++++ .../RedfishRestExDxe/RedfishRestExProtocol.c | 735 ++++++++++++++++ 12 files changed, 3306 insertions(+) create mode 100644 RedfishPkg/RedfishRestExDxe/ComponentName.c create mode 100644 RedfishPkg/RedfishRestExDxe/RedfishRestExDriver.c create mode 100644 RedfishPkg/RedfishRestExDxe/RedfishRestExDriver.h create mode 100644 RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf create mode 100644 RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.uni create mode 100644 RedfishPkg/RedfishRestExDxe/RedfishRestExDxeExtra.uni create mode 100644 RedfishPkg/RedfishRestExDxe/RedfishRestExImpl.c create mode 100644 RedfishPkg/RedfishRestExDxe/RedfishRestExInternal.h create mode 100644 RedfishPkg/RedfishRestExDxe/RedfishRestExProtocol.c diff --git a/RedfishPkg/Redfish.fdf.inc b/RedfishPkg/Redfish.fdf.inc index 19de479a80..429156aa78 100644 --- a/RedfishPkg/Redfish.fdf.inc +++ b/RedfishPkg/Redfish.fdf.inc @@ -13,4 +13,5 @@ !if $(REDFISH_ENABLE) == TRUE INF RedfishPkg/RestJsonStructureDxe/RestJsonStructureDxe.inf INF RedfishPkg/RedfishHostInterfaceDxe/RedfishHostInterfaceDxe.inf + INF RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf !endif diff --git a/RedfishPkg/RedfishComponents.dsc.inc b/RedfishPkg/RedfishComponents.dsc.inc index ac1b57ed8f..3b9429db09 100644 --- a/RedfishPkg/RedfishComponents.dsc.inc +++ b/RedfishPkg/RedfishComponents.dsc.inc @@ -15,4 +15,5 @@ !if $(REDFISH_ENABLE) == TRUE RedfishPkg/RestJsonStructureDxe/RestJsonStructureDxe.inf RedfishPkg/RedfishHostInterfaceDxe/RedfishHostInterfaceDxe.inf + RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf !endif diff --git a/RedfishPkg/RedfishPkg.dsc b/RedfishPkg/RedfishPkg.dsc index 94e7127bc6..c05e81af7b 100644 --- a/RedfishPkg/RedfishPkg.dsc +++ b/RedfishPkg/RedfishPkg.dsc @@ -32,6 +32,10 @@ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf RedfishPlatformHostInterfaceLib|RedfishPkg/Library/PlatformHostInterfaceLibNull/PlatformHostInterfaceLibNull.inf + HttpLib|NetworkPkg/Library/DxeHttpLib/DxeHttpLib.inf + HttpIoLib|NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf + NetLib|NetworkPkg/Library/DxeNetLib/DxeNetLib.inf + DpcLib|NetworkPkg/Library/DxeDpcLib/DxeDpcLib.inf [LibraryClasses.ARM, LibraryClasses.AARCH64] # diff --git a/RedfishPkg/RedfishRestExDxe/ComponentName.c b/RedfishPkg/RedfishRestExDxe/ComponentName.c new file mode 100644 index 0000000000..3674178412 --- /dev/null +++ b/RedfishPkg/RedfishRestExDxe/ComponentName.c @@ -0,0 +1,222 @@ +/** @file + Implementation of EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL + protocol. + + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ (C) Copyright 2020 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include + +#include + +#include +#include + +// +// EFI Component Name Functions +// +/** + Retrieves a Unicode string that is the user-readable name of the EFI Driver. + + @param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param[in] Language A pointer to a three-character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + @param[out] DriverName A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + @param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param[in] ControllerHandle The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + @param[in] ChildHandle The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + @param[in] Language A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + @param[out] ControllerName A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language, from the point of view of the driver specified + by This. + + @retval EFI_SUCCESS The Unicode string for the user-readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +/// +/// Component Name Protocol instance +/// +GLOBAL_REMOVE_IF_UNREFERENCED +EFI_COMPONENT_NAME_PROTOCOL gRedfishRestExComponentName = { + RedfishRestExComponentNameGetDriverName, + RedfishRestExComponentNameGetControllerName, + "eng" +}; + +/// +/// Component Name 2 Protocol instance +/// +GLOBAL_REMOVE_IF_UNREFERENCED +EFI_COMPONENT_NAME2_PROTOCOL gRedfishRestExComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) RedfishRestExComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) RedfishRestExComponentNameGetControllerName, + "en" +}; + +/// +/// Table of driver names +/// +GLOBAL_REMOVE_IF_UNREFERENCED +EFI_UNICODE_STRING_TABLE mRedfishRestExDriverNameTable[] = { + { "eng;en", (CHAR16 *)L"Redfish RestEx Network Service Driver" }, + { NULL, NULL } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gRedfishRestExControllerNameTable = NULL; + +/** + Retrieves a Unicode string that is the user-readable name of the EFI Driver. + + @param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param[in] Language A pointer to a three-character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + @param[out] DriverName A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mRedfishRestExDriverNameTable, + DriverName, + (BOOLEAN)(This == &gRedfishRestExComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + @param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param[in] ControllerHandle The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + @param[in] ChildHandle The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + @param[in] Language A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + @param[out] ControllerName A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language, from the point of view of the driver specified + by This. + + @retval EFI_SUCCESS The Unicode string for the user-readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/RedfishPkg/RedfishRestExDxe/RedfishRestExDriver.c b/RedfishPkg/RedfishRestExDxe/RedfishRestExDriver.c new file mode 100644 index 0000000000..87327a8549 --- /dev/null +++ b/RedfishPkg/RedfishRestExDxe/RedfishRestExDriver.c @@ -0,0 +1,831 @@ +/** @file + The driver binding and service binding protocol for Redfish RestExDxe driver. + + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ (C) Copyright 2020 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include "RedfishRestExDriver.h" + +EFI_DRIVER_BINDING_PROTOCOL gRedfishRestExDriverBinding = { + RedfishRestExDriverBindingSupported, + RedfishRestExDriverBindingStart, + RedfishRestExDriverBindingStop, + REDFISH_RESTEX_DRIVER_VERSION, + NULL, + NULL +}; + +EFI_SERVICE_BINDING_PROTOCOL mRedfishRestExServiceBinding = { + RedfishRestExServiceBindingCreateChild, + RedfishRestExServiceBindingDestroyChild +}; + +/** + Callback function which provided by user to remove one node in NetDestroyLinkList process. + + @param[in] Entry The entry to be removed. + @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList. + + @retval EFI_SUCCESS The entry has been removed successfully. + @retval Others Fail to remove the entry. + +**/ +EFI_STATUS +EFIAPI +RestExDestroyChildEntryInHandleBuffer ( + IN LIST_ENTRY *Entry, + IN VOID *Context + ) +{ + RESTEX_INSTANCE *Instance; + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + UINTN NumberOfChildren; + EFI_HANDLE *ChildHandleBuffer; + + if (Entry == NULL || Context == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = NET_LIST_USER_STRUCT_S (Entry, RESTEX_INSTANCE, Link, RESTEX_INSTANCE_SIGNATURE); + ServiceBinding = ((RESTEX_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding; + NumberOfChildren = ((RESTEX_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren; + ChildHandleBuffer = ((RESTEX_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer; + + if (!NetIsInHandleBuffer (Instance->ChildHandle, NumberOfChildren, ChildHandleBuffer)) { + return EFI_SUCCESS; + } + + return ServiceBinding->DestroyChild (ServiceBinding, Instance->ChildHandle); +} + +/** + Destroy the RestEx instance and recycle the resources. + + @param[in] Instance The pointer to the RestEx instance. + +**/ +VOID +RestExDestroyInstance ( + IN RESTEX_INSTANCE *Instance + ) +{ + HttpIoDestroyIo (&(Instance->HttpIo)); + + FreePool (Instance); +} + +/** + Create the RestEx instance and initialize it. + + @param[in] Service The pointer to the RestEx service. + @param[out] Instance The pointer to the RestEx instance. + + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_SUCCESS The RestEx instance is created. + +**/ +EFI_STATUS +RestExCreateInstance ( + IN RESTEX_SERVICE *Service, + OUT RESTEX_INSTANCE **Instance + ) +{ + RESTEX_INSTANCE *RestExIns; + EFI_STATUS Status; + + *Instance = NULL; + Status = EFI_SUCCESS; + + RestExIns = AllocateZeroPool (sizeof (RESTEX_INSTANCE)); + if (RestExIns == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + RestExIns->Signature = RESTEX_INSTANCE_SIGNATURE; + InitializeListHead (&RestExIns->Link); + RestExIns->InDestroy = FALSE; + RestExIns->Service = Service; + + CopyMem (&RestExIns->RestEx, &mRedfishRestExProtocol, sizeof (RestExIns->RestEx)); + + // + // Create a HTTP_IO to access the HTTP service. + // + Status = HttpIoCreateIo ( + RestExIns->Service->ImageHandle, + RestExIns->Service->ControllerHandle, + IP_VERSION_4, + NULL, + NULL, + NULL, + &(RestExIns->HttpIo) + ); + if (EFI_ERROR (Status)) { + FreePool (RestExIns); + return Status; + } + + *Instance = RestExIns; + + return EFI_SUCCESS; +} + +/** + Release all the resource used the RestEx service binding instance. + + @param[in] RestExSb The RestEx service binding instance. + +**/ +VOID +RestExDestroyService ( + IN RESTEX_SERVICE *RestExSb + ) +{ + if (RestExSb->HttpChildHandle != NULL) { + gBS->CloseProtocol ( + RestExSb->HttpChildHandle, + &gEfiHttpProtocolGuid, + RestExSb->ImageHandle, + RestExSb->ControllerHandle + ); + + NetLibDestroyServiceChild ( + RestExSb->ControllerHandle, + RestExSb->ImageHandle, + &gEfiHttpServiceBindingProtocolGuid, + RestExSb->HttpChildHandle + ); + + RestExSb->HttpChildHandle = NULL; + } + + gBS->UninstallProtocolInterface ( + RestExSb->ControllerHandle, + &gEfiCallerIdGuid, + &RestExSb->Id + ); + + FreePool (RestExSb); +} + +/** + Check the NIC controller handle represents an in-band or out-of-band Redfish host + interface device. If not in-band, treat it as out-of-band interface device. + + @param[in] Controller The NIC controller handle needs to be checked. + + @return EFI_REST_EX_SERVICE_ACCESS_MODE of the device. + +**/ +EFI_REST_EX_SERVICE_ACCESS_MODE +RestExServiceAccessMode ( + IN EFI_HANDLE Controller + ) +{ + // + // This is EFI REST EX driver instance to connect + // to Redfish service using HTTP in out of band. + // + if (FixedPcdGetBool (PcdRedfishRestExServiceAccessModeInBand)) { + return EfiRestExServiceInBandAccess; + } else { + return EfiRestExServiceOutOfBandAccess; + } +} + +/** + Create then initialize a RestEx service binding instance. + + @param[in] Controller The controller to install the RestEx service + binding on. + @param[in] Image The driver binding image of the RestEx driver. + @param[out] Service The variable to receive the created service + binding instance. + + @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance. + @retval EFI_SUCCESS The service instance is created for the controller. + +**/ +EFI_STATUS +RestExCreateService ( + IN EFI_HANDLE Controller, + IN EFI_HANDLE Image, + OUT RESTEX_SERVICE **Service + ) +{ + EFI_STATUS Status; + RESTEX_SERVICE *RestExSb; + + Status = EFI_SUCCESS; + RestExSb = NULL; + + *Service = NULL; + + RestExSb = AllocateZeroPool (sizeof (RESTEX_SERVICE)); + if (RestExSb == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + RestExSb->Signature = RESTEX_SERVICE_SIGNATURE; + + RestExSb->ServiceBinding = mRedfishRestExServiceBinding; + + RestExSb->RestExChildrenNum = 0; + InitializeListHead (&RestExSb->RestExChildrenList); + + RestExSb->ControllerHandle = Controller; + RestExSb->ImageHandle = Image; + + RestExSb->RestExServiceInfo.EfiRestExServiceInfoV10.EfiRestExServiceInfoHeader.Length = sizeof (EFI_REST_EX_SERVICE_INFO); + RestExSb->RestExServiceInfo.EfiRestExServiceInfoV10.EfiRestExServiceInfoHeader.RestServiceInfoVer.Major = 1; + RestExSb->RestExServiceInfo.EfiRestExServiceInfoV10.EfiRestExServiceInfoHeader.RestServiceInfoVer.Minor = 0; + RestExSb->RestExServiceInfo.EfiRestExServiceInfoV10.RestServiceType = EfiRestExServiceRedfish; + RestExSb->RestExServiceInfo.EfiRestExServiceInfoV10.RestServiceAccessMode = RestExServiceAccessMode (Controller); + RestExSb->RestExServiceInfo.EfiRestExServiceInfoV10.RestExConfigType = EfiRestExConfigHttp; + RestExSb->RestExServiceInfo.EfiRestExServiceInfoV10.RestExConfigDataLength = sizeof (EFI_REST_EX_HTTP_CONFIG_DATA); + + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiCallerIdGuid, + EFI_NATIVE_INTERFACE, + &RestExSb->Id + ); + if (EFI_ERROR (Status)) { + FreePool (RestExSb); + RestExSb = NULL; + } + + *Service = RestExSb; + return Status; +} + +/** + This is the declaration of an EFI image entry point. This entry point is + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including + both device drivers and bus drivers. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval Others An unexpected error occurred. +**/ +EFI_STATUS +EFIAPI +RedfishRestExDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + // + // Install the RestEx Driver Binding Protocol. + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gRedfishRestExDriverBinding, + ImageHandle, + &gRedfishRestExComponentName, + &gRedfishRestExComponentName2 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return Status; +} + +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Because ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +RedfishRestExDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + + // + // Test for the HttpServiceBinding Protocol. + // + return gBS->OpenProtocol ( + ControllerHandle, + &gEfiHttpServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + +} + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + RESTEX_SERVICE *RestExSb; + EFI_STATUS Status; + UINT32 *Id; + VOID *Interface; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiCallerIdGuid, + (VOID **) &Id, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return EFI_ALREADY_STARTED; + } + + Status = RestExCreateService (ControllerHandle, This->DriverBindingHandle, &RestExSb); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (RestExSb != NULL); + + // + // Create a Http child instance, but do not configure it. + // This will establish the parent-child relationship. + // + Status = NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiHttpServiceBindingProtocolGuid, + &RestExSb->HttpChildHandle + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + RestExSb->HttpChildHandle, + &gEfiHttpProtocolGuid, + &Interface, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Install the RestEx ServiceBinding Protocol onto ControllerHandle. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiRestExServiceBindingProtocolGuid, + &RestExSb->ServiceBinding, + NULL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + return EFI_SUCCESS; + +ON_ERROR: + RestExDestroyService (RestExSb); + + return Status; +} + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + RESTEX_SERVICE *RestExSb; + EFI_HANDLE NicHandle; + EFI_STATUS Status; + LIST_ENTRY *List; + RESTEX_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context; + + // + // RestEx driver opens HTTP child, So, Controller is a HTTP + // child handle. Locate the Nic handle first. Then get the + // RestEx private data back. + // + NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid); + if (NicHandle == NULL) { + return EFI_SUCCESS; + } + + Status = gBS->OpenProtocol ( + NicHandle, + &gEfiRestExServiceBindingProtocolGuid, + (VOID **) &ServiceBinding, + This->DriverBindingHandle, + NicHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + RestExSb = RESTEX_SERVICE_FROM_THIS (ServiceBinding); + + if (!IsListEmpty (&RestExSb->RestExChildrenList)) { + // + // Destroy the RestEx child instance in ChildHandleBuffer. + // + List = &RestExSb->RestExChildrenList; + Context.ServiceBinding = ServiceBinding; + Context.NumberOfChildren = NumberOfChildren; + Context.ChildHandleBuffer = ChildHandleBuffer; + Status = NetDestroyLinkList ( + List, + RestExDestroyChildEntryInHandleBuffer, + &Context, + NULL + ); + } + + if (NumberOfChildren == 0 && IsListEmpty (&RestExSb->RestExChildrenList)) { + gBS->UninstallProtocolInterface ( + NicHandle, + &gEfiRestExServiceBindingProtocolGuid, + ServiceBinding + ); + + RestExDestroyService (RestExSb); + + if (gRedfishRestExControllerNameTable != NULL) { + FreeUnicodeStringTable (gRedfishRestExControllerNameTable); + gRedfishRestExControllerNameTable = NULL; + } + + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + Creates a child handle and installs a protocol. + + The CreateChild() function installs a protocol on ChildHandle. + If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle. + If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle. + + @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL, + then a new handle is created. If it is a pointer to an existing UEFI handle, + then the protocol is added to the existing UEFI handle. + + @retval EFI_SUCCES The protocol was added to ChildHandle. + @retval EFI_INVALID_PARAMETER ChildHandle is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create + the child + @retval other The child handle was not created + +**/ +EFI_STATUS +EFIAPI +RedfishRestExServiceBindingCreateChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE *ChildHandle + ) +{ + RESTEX_SERVICE *RestExSb; + RESTEX_INSTANCE *Instance; + EFI_STATUS Status; + EFI_TPL OldTpl; + VOID *Http; + + if ((This == NULL) || (ChildHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + RestExSb = RESTEX_SERVICE_FROM_THIS (This); + + Status = RestExCreateInstance (RestExSb, &Instance); + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (Instance != NULL); + + // + // Install the RestEx protocol onto ChildHandle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + ChildHandle, + &gEfiRestExProtocolGuid, + &Instance->RestEx, + NULL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Instance->ChildHandle = *ChildHandle; + + // + // Open the Http protocol BY_CHILD. + // + Status = gBS->OpenProtocol ( + RestExSb->HttpChildHandle, + &gEfiHttpProtocolGuid, + (VOID **) &Http, + gRedfishRestExDriverBinding.DriverBindingHandle, + Instance->ChildHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces ( + Instance->ChildHandle, + &gEfiRestExProtocolGuid, + &Instance->RestEx, + NULL + ); + + goto ON_ERROR; + } + + // + // Open the Http protocol by child. + // + Status = gBS->OpenProtocol ( + Instance->HttpIo.Handle, + &gEfiHttpProtocolGuid, + (VOID **) &Http, + gRedfishRestExDriverBinding.DriverBindingHandle, + Instance->ChildHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + // + // Close the Http protocol. + // + gBS->CloseProtocol ( + RestExSb->HttpChildHandle, + &gEfiHttpProtocolGuid, + gRedfishRestExDriverBinding.DriverBindingHandle, + ChildHandle + ); + + gBS->UninstallMultipleProtocolInterfaces ( + Instance->ChildHandle, + &gEfiRestExProtocolGuid, + &Instance->RestEx, + NULL + ); + + goto ON_ERROR; + } + + // + // Add it to the parent's child list. + // + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + InsertTailList (&RestExSb->RestExChildrenList, &Instance->Link); + RestExSb->RestExChildrenNum++; + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; + +ON_ERROR: + + RestExDestroyInstance (Instance); + return Status; +} + +/** + Destroys a child handle with a protocol installed on it. + + The DestroyChild() function does the opposite of CreateChild(). It removes a protocol + that was installed by CreateChild() from ChildHandle. If the removed protocol is the + last protocol on ChildHandle, then ChildHandle is destroyed. + + @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param[in] ChildHandle Handle of the child to destroy + + @retval EFI_SUCCES The protocol was removed from ChildHandle. + @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed. + @retval EFI_INVALID_PARAMETER Child handle is NULL. + @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle + because its services are being used. + @retval other The child handle was not destroyed + +**/ +EFI_STATUS +EFIAPI +RedfishRestExServiceBindingDestroyChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE ChildHandle + ) +{ + RESTEX_SERVICE *RestExSb; + RESTEX_INSTANCE *Instance; + + EFI_REST_EX_PROTOCOL *RestEx; + EFI_STATUS Status; + EFI_TPL OldTpl; + + if ((This == NULL) || (ChildHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Retrieve the private context data structures + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiRestExProtocolGuid, + (VOID **) &RestEx, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Instance = RESTEX_INSTANCE_FROM_THIS (RestEx); + RestExSb = RESTEX_SERVICE_FROM_THIS (This); + + if (Instance->Service != RestExSb) { + return EFI_INVALID_PARAMETER; + } + + if (Instance->InDestroy) { + return EFI_SUCCESS; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance->InDestroy = TRUE; + + // + // Close the Http protocol. + // + gBS->CloseProtocol ( + RestExSb->HttpChildHandle, + &gEfiHttpProtocolGuid, + gRedfishRestExDriverBinding.DriverBindingHandle, + ChildHandle + ); + + gBS->CloseProtocol ( + Instance->HttpIo.Handle, + &gEfiHttpProtocolGuid, + gRedfishRestExDriverBinding.DriverBindingHandle, + ChildHandle + ); + + + gBS->RestoreTPL (OldTpl); + + // + // Uninstall the RestEx protocol first to enable a top down destruction. + // + Status = gBS->UninstallProtocolInterface ( + ChildHandle, + &gEfiRestExProtocolGuid, + RestEx + ); + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + if (EFI_ERROR (Status)) { + Instance->InDestroy = FALSE; + gBS->RestoreTPL (OldTpl); + return Status; + } + + RemoveEntryList (&Instance->Link); + RestExSb->RestExChildrenNum--; + + gBS->RestoreTPL (OldTpl); + + RestExDestroyInstance (Instance); + return EFI_SUCCESS; +} + diff --git a/RedfishPkg/RedfishRestExDxe/RedfishRestExDriver.h b/RedfishPkg/RedfishRestExDxe/RedfishRestExDriver.h new file mode 100644 index 0000000000..6743ced23c --- /dev/null +++ b/RedfishPkg/RedfishRestExDxe/RedfishRestExDriver.h @@ -0,0 +1,650 @@ +/** @file + RedfishRestExDxe support functions definitions. + + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ (C) Copyright 2020 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef EFI_REDFISH_RESTEX_DRIVER_H_ +#define EFI_REDFISH_RESTEX_DRIVER_H_ + +/// +/// Libraries classes +/// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/// +/// UEFI Driver Model Protocols +/// +#include +#include +#include + +/// +/// Protocol instances +/// +extern EFI_COMPONENT_NAME_PROTOCOL gRedfishRestExComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gRedfishRestExComponentName2; +extern EFI_UNICODE_STRING_TABLE *gRedfishRestExControllerNameTable; + +extern EFI_DRIVER_BINDING_PROTOCOL gRedfishRestExDriverBinding; +extern EFI_SERVICE_BINDING_PROTOCOL mRedfishRestExServiceBinding; +extern EFI_REST_EX_PROTOCOL mRedfishRestExProtocol; +/// +/// RestEx service block +/// +typedef struct _RESTEX_SERVICE RESTEX_SERVICE; + +/// +/// RestEx instance block +/// +typedef struct _RESTEX_INSTANCE RESTEX_INSTANCE; + +/// +/// Driver Version +/// +#define REDFISH_RESTEX_DRIVER_VERSION 0x0100 + +#define RESTEX_SERVICE_SIGNATURE SIGNATURE_32 ('R', 'E', 'S', 'S') +#define RESTEX_INSTANCE_SIGNATURE SIGNATURE_32 ('R', 'E', 'I', 'S') + +#define RESTEX_SERVICE_FROM_THIS(a) \ + CR (a, RESTEX_SERVICE, ServiceBinding, RESTEX_SERVICE_SIGNATURE) + +#define RESTEX_INSTANCE_FROM_THIS(a) \ + CR (a, RESTEX_INSTANCE, RestEx, RESTEX_INSTANCE_SIGNATURE) + + +#define RESTEX_STATE_UNCONFIGED 0 +#define RESTEX_STATE_CONFIGED 1 + +struct _RESTEX_SERVICE { + UINT32 Signature; + EFI_SERVICE_BINDING_PROTOCOL ServiceBinding; + + UINT16 RestExChildrenNum; + LIST_ENTRY RestExChildrenList; + + EFI_HANDLE ControllerHandle; + EFI_HANDLE ImageHandle; + + // + // Use to establish the parent-child relationship. + // + EFI_HANDLE HttpChildHandle; + + UINT32 Id; + + EFI_REST_EX_SERVICE_INFO RestExServiceInfo; +}; + +#define RESTEX_INSTANCE_FLAGS_TLS_RETRY 0x00000001 +#define RESTEX_INSTANCE_FLAGS_TCP_ERROR_RETRY 0x00000002 + +struct _RESTEX_INSTANCE { + UINT32 Signature; + LIST_ENTRY Link; + + EFI_REST_EX_PROTOCOL RestEx; + + INTN State; + BOOLEAN InDestroy; + + RESTEX_SERVICE *Service; + EFI_HANDLE ChildHandle; + + EFI_REST_EX_CONFIG_DATA ConfigData; + + // + // HTTP_IO to access the HTTP service + // + HTTP_IO HttpIo; + + UINT32 Flags; +}; + +typedef struct { + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + UINTN NumberOfChildren; + EFI_HANDLE *ChildHandleBuffer; +} RESTEX_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT; + +/** + Provides a simple HTTP-like interface to send and receive resources from a REST service. + + The SendReceive() function sends an HTTP request to this REST service, and returns a + response when the data is retrieved from the service. RequestMessage contains the HTTP + request to the REST resource identified by RequestMessage.Request.Url. The + ResponseMessage is the returned HTTP response for that request, including any HTTP + status. + + @param[in] This Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[in] RequestMessage Pointer to the HTTP request data for this resource + @param[out] ResponseMessage Pointer to the HTTP response data obtained for this requested. + + @retval EFI_SUCCESS operation succeeded. + @retval EFI_INVALID_PARAMETER This, RequestMessage, or ResponseMessage are NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExSendReceive ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_HTTP_MESSAGE *RequestMessage, + OUT EFI_HTTP_MESSAGE *ResponseMessage + ); + +/** + Obtain the current time from this REST service instance. + + The GetServiceTime() function is an optional interface to obtain the current time from + this REST service instance. If this REST service does not support to retrieve the time, + this function returns EFI_UNSUPPORTED. This function must returns EFI_UNSUPPORTED if + EFI_REST_EX_SERVICE_TYPE returned in EFI_REST_EX_SERVICE_INFO from GetService() is + EFI_REST_EX_SERVICE_UNSPECIFIC. + + @param[in] This Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[out] Time A pointer to storage to receive a snapshot of the current time of + the REST service. + + @retval EFI_SUCCESS operation succeeded. + @retval EFI_INVALID_PARAMETER This or Time are NULL. + @retval EFI_UNSUPPORTED The RESTful service does not support returning the time. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_NOT_READY The configuration of this instance is not set yet. Configure() must + be executed and returns successfully prior to invoke this function. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExGetServiceTime ( + IN EFI_REST_EX_PROTOCOL *This, + OUT EFI_TIME *Time + ); + +/** + This function returns the information of REST service provided by this EFI REST EX driver instance. + + The information such as the type of REST service and the access mode of REST EX driver instance + (In-band or Out-of-band) are described in EFI_REST_EX_SERVICE_INFO structure. For the vendor-specific + REST service, vendor-specific REST service information is returned in VendorSpecifcData. + REST EX driver designer is well know what REST service this REST EX driver instance intends to + communicate with. The designer also well know this driver instance is used to talk to BMC through + specific platform mechanism or talk to REST server through UEFI HTTP protocol. REST EX driver is + responsible to fill up the correct information in EFI_REST_EX_SERVICE_INFO. EFI_REST_EX_SERVICE_INFO + is referred by EFI REST clients to pickup the proper EFI REST EX driver instance to get and set resource. + GetService() is a basic and mandatory function which must be able to use even Configure() is not invoked + in previously. + + @param[in] This Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[out] RestExServiceInfo Pointer to receive a pointer to EFI_REST_EX_SERVICE_INFO structure. The + format of EFI_REST_EX_SERVICE_INFO is version controlled for the future + extension. The version of EFI_REST_EX_SERVICE_INFO structure is returned + in the header within this structure. EFI REST client refers to the correct + format of structure according to the version number. The pointer to + EFI_REST_EX_SERVICE_INFO is a memory block allocated by EFI REST EX driver + instance. That is caller's responsibility to free this memory when this + structure is no longer needed. Refer to Related Definitions below for the + definitions of EFI_REST_EX_SERVICE_INFO structure. + + @retval EFI_SUCCESS EFI_REST_EX_SERVICE_INFO is returned in RestExServiceInfo. This function + is not supported in this REST EX Protocol driver instance. + @retval EFI_UNSUPPORTED This function is not supported in this REST EX Protocol driver instance. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExGetService ( + IN EFI_REST_EX_PROTOCOL *This, + OUT EFI_REST_EX_SERVICE_INFO **RestExServiceInfo + ); + +/** + This function returns operational configuration of current EFI REST EX child instance. + + This function returns the current configuration of EFI REST EX child instance. The format of + operational configuration depends on the implementation of EFI REST EX driver instance. For + example, HTTP-aware EFI REST EX driver instance uses EFI HTTP protocol as the undying protocol + to communicate with REST service. In this case, the type of configuration is + EFI_REST_EX_CONFIG_TYPE_HTTP returned from GetService(). EFI_HTTP_CONFIG_DATA is used as EFI REST + EX configuration format and returned to EFI REST client. User has to type cast RestExConfigData + to EFI_HTTP_CONFIG_DATA. For those non HTTP-aware REST EX driver instances, the type of configuration + is EFI_REST_EX_CONFIG_TYPE_UNSPECIFIC returned from GetService(). In this case, the format of + returning data could be non industrial. Instead, the format of configuration data is system/platform + specific definition such as BMC mechanism used in EFI REST EX driver instance. EFI REST client and + EFI REST EX driver instance have to refer to the specific system /platform spec which is out of UEFI scope. + + @param[in] This This is the EFI_REST_EX_PROTOCOL instance. + @param[out] RestExConfigData Pointer to receive a pointer to EFI_REST_EX_CONFIG_DATA. + The memory allocated for configuration data should be freed + by caller. See Related Definitions for the details. + + @retval EFI_SUCCESS EFI_REST_EX_CONFIG_DATA is returned in successfully. + @retval EFI_UNSUPPORTED This function is not supported in this REST EX Protocol driver instance. + @retval EFI_NOT_READY The configuration of this instance is not set yet. Configure() must be + executed and returns successfully prior to invoke this function. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExGetModeData ( + IN EFI_REST_EX_PROTOCOL *This, + OUT EFI_REST_EX_CONFIG_DATA *RestExConfigData + ); + +/** + This function is used to configure EFI REST EX child instance. + + This function is used to configure the setting of underlying protocol of REST EX child + instance. The type of configuration is according to the implementation of EFI REST EX + driver instance. For example, HTTP-aware EFI REST EX driver instance uses EFI HTTP protocol + as the undying protocol to communicate with REST service. The type of configuration is + EFI_REST_EX_CONFIG_TYPE_HTTP and RestExConfigData is the same format with EFI_HTTP_CONFIG_DATA. + Akin to HTTP configuration, REST EX child instance can be configure to use different HTTP + local access point for the data transmission. Multiple REST clients may use different + configuration of HTTP to distinguish themselves, such as to use the different TCP port. + For those non HTTP-aware REST EX driver instance, the type of configuration is + EFI_REST_EX_CONFIG_TYPE_UNSPECIFIC. RestExConfigData refers to the non industrial standard. + Instead, the format of configuration data is system/platform specific definition such as BMC. + In this case, EFI REST client and EFI REST EX driver instance have to refer to the specific + system/platform spec which is out of the UEFI scope. Besides GetService()function, no other + EFI REST EX functions can be executed by this instance until Configure()is executed and returns + successfully. All other functions must returns EFI_NOT_READY if this instance is not configured + yet. Set RestExConfigData to NULL means to put EFI REST EX child instance into the unconfigured + state. + + @param[in] This This is the EFI_REST_EX_PROTOCOL instance. + @param[in] RestExConfigData Pointer to EFI_REST_EX_CONFIG_DATA. See Related Definitions in + GetModeData() protocol interface. + + @retval EFI_SUCCESS EFI_REST_EX_CONFIG_DATA is set in successfully. + @retval EFI_DEVICE_ERROR Configuration for this REST EX child instance is failed with the given + EFI_REST_EX_CONFIG_DATA. + @retval EFI_UNSUPPORTED This function is not supported in this REST EX Protocol driver instance. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExConfigure ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_REST_EX_CONFIG_DATA RestExConfigData + ); + +/** + This function sends REST request to REST service and signal caller's event asynchronously when + the final response is received by REST EX Protocol driver instance. + + The essential design of this function is to handle asynchronous send/receive implicitly according + to REST service asynchronous request mechanism. Caller will get the notification once the response + is returned from REST service. + + @param[in] This This is the EFI_REST_EX_PROTOCOL instance. + @param[in] RequestMessage This is the HTTP request message sent to REST service. Set RequestMessage + to NULL to cancel the previous asynchronous request associated with the + corresponding RestExToken. See descriptions for the details. + @param[in] RestExToken REST EX token which REST EX Protocol instance uses to notify REST client + the status of response of asynchronous REST request. See related definition + of EFI_REST_EX_TOKEN. + @param[in] TimeOutInMilliSeconds The pointer to the timeout in milliseconds which REST EX Protocol driver + instance refers as the duration to drop asynchronous REST request. NULL + pointer means no timeout for this REST request. REST EX Protocol driver + signals caller's event with EFI_STATUS set to EFI_TIMEOUT in RestExToken + if REST EX Protocol can't get the response from REST service within + TimeOutInMilliSeconds. + + @retval EFI_SUCCESS Asynchronous REST request is established. + @retval EFI_UNSUPPORTED This REST EX Protocol driver instance doesn't support asynchronous request. + @retval EFI_TIMEOUT Asynchronous REST request is not established and timeout is expired. + @retval EFI_ABORT Previous asynchronous REST request has been canceled. + @retval EFI_DEVICE_ERROR Otherwise, returns EFI_DEVICE_ERROR for other errors according to HTTP Status Code. + @retval EFI_NOT_READY The configuration of this instance is not set yet. Configure() must be executed + and returns successfully prior to invoke this function. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExAyncSendReceive ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_HTTP_MESSAGE *RequestMessage OPTIONAL, + IN EFI_REST_EX_TOKEN *RestExToken, + IN UINTN *TimeOutInMilliSeconds OPTIONAL + ); + +/** + This function sends REST request to a REST Event service and signals caller's event + token asynchronously when the URI resource change event is received by REST EX + Protocol driver instance. + + The essential design of this function is to monitor event implicitly according to + REST service event service mechanism. Caller will get the notification if certain + resource is changed. + + @param[in] This This is the EFI_REST_EX_PROTOCOL instance. + @param[in] RequestMessage This is the HTTP request message sent to REST service. Set RequestMessage + to NULL to cancel the previous event service associated with the corresponding + RestExToken. See descriptions for the details. + @param[in] RestExToken REST EX token which REST EX Protocol driver instance uses to notify REST client + the URI resource which monitored by REST client has been changed. See the related + definition of EFI_REST_EX_TOKEN in EFI_REST_EX_PROTOCOL.AsyncSendReceive(). + + @retval EFI_SUCCESS Asynchronous REST request is established. + @retval EFI_UNSUPPORTED This REST EX Protocol driver instance doesn't support asynchronous request. + @retval EFI_ABORT Previous asynchronous REST request has been canceled or event subscription has been + delete from service. + @retval EFI_DEVICE_ERROR Otherwise, returns EFI_DEVICE_ERROR for other errors according to HTTP Status Code. + @retval EFI_NOT_READY The configuration of this instance is not set yet. Configure() must be executed + and returns successfully prior to invoke this function. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExEventService ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_HTTP_MESSAGE *RequestMessage OPTIONAL, + IN EFI_REST_EX_TOKEN *RestExToken + ); +/** + Create a new TLS session becuase the previous on is closed. + status. + + @param[in] Instance Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @retval EFI_SUCCESS operation succeeded. + @retval EFI Errors Other errors. + +**/ +EFI_STATUS +ResetHttpTslSession ( + IN RESTEX_INSTANCE *Instance +); + + +/** + Callback function which provided by user to remove one node in NetDestroyLinkList process. + + @param[in] Entry The entry to be removed. + @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList. + + @retval EFI_SUCCESS The entry has been removed successfully. + @retval Others Fail to remove the entry. + +**/ +EFI_STATUS +EFIAPI +RestExDestroyChildEntryInHandleBuffer ( + IN LIST_ENTRY *Entry, + IN VOID *Context + ); + +/** + Destroy the RestEx instance and recycle the resources. + + @param[in] Instance The pointer to the RestEx instance. + +**/ +VOID +RestExDestroyInstance ( + IN RESTEX_INSTANCE *Instance + ); + +/** + Create the RestEx instance and initialize it. + + @param[in] Service The pointer to the RestEx service. + @param[out] Instance The pointer to the RestEx instance. + + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_SUCCESS The RestEx instance is created. + +**/ +EFI_STATUS +RestExCreateInstance ( + IN RESTEX_SERVICE *Service, + OUT RESTEX_INSTANCE **Instance + ); + + +/** + Release all the resource used the RestEx service binding instance. + + @param RestExSb The RestEx service binding instance. + +**/ +VOID +RestExDestroyService ( + IN RESTEX_SERVICE *RestExSb + ); + +/** + Create then initialize a RestEx service binding instance. + + @param[in] Controller The controller to install the RestEx service + binding on. + @param[in] Image The driver binding image of the RestEx driver. + @param[out] Service The variable to receive the created service + binding instance. + + @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance. + @retval EFI_SUCCESS The service instance is created for the controller. + +**/ +EFI_STATUS +RestExCreateService ( + IN EFI_HANDLE Controller, + IN EFI_HANDLE Image, + OUT RESTEX_SERVICE **Service + ); + +/** + This is the declaration of an EFI image entry point. This entry point is + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including + both device drivers and bus drivers. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval Others An unexpected error occurred. +**/ +EFI_STATUS +EFIAPI +RedfishRestExDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Because ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +RedfishRestExDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); + +/** + Creates a child handle and installs a protocol. + + The CreateChild() function installs a protocol on ChildHandle. + If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle. + If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle. + + @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL, + then a new handle is created. If it is a pointer to an existing UEFI handle, + then the protocol is added to the existing UEFI handle. + + @retval EFI_SUCCES The protocol was added to ChildHandle. + @retval EFI_INVALID_PARAMETER ChildHandle is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create + the child + @retval other The child handle was not created + +**/ +EFI_STATUS +EFIAPI +RedfishRestExServiceBindingCreateChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE *ChildHandle + ); + +/** + Destroys a child handle with a protocol installed on it. + + The DestroyChild() function does the opposite of CreateChild(). It removes a protocol + that was installed by CreateChild() from ChildHandle. If the removed protocol is the + last protocol on ChildHandle, then ChildHandle is destroyed. + + @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param[in] ChildHandle Handle of the child to destroy + + @retval EFI_SUCCES The protocol was removed from ChildHandle. + @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed. + @retval EFI_INVALID_PARAMETER Child handle is NULL. + @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle + because its services are being used. + @retval other The child handle was not destroyed + +**/ +EFI_STATUS +EFIAPI +RedfishRestExServiceBindingDestroyChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE ChildHandle + ); +#endif diff --git a/RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf b/RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf new file mode 100644 index 0000000000..75437b086a --- /dev/null +++ b/RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.inf @@ -0,0 +1,63 @@ +## @file +# Implementation of Redfish EFI_REST_EX_PROTOCOL interfaces. +# +# Copyright (c) 2019, Intel Corporation. All rights reserved.
+# (C) Copyright 2020 Hewlett Packard Enterprise Development LP
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001b + BASE_NAME = RedfishRestExDxe + FILE_GUID = B64702DA-E6B5-43c8-8CE8-D253071E9D6C + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = RedfishRestExDriverEntryPoint + UNLOAD_IMAGE = NetLibDefaultUnload + MODULE_UNI_FILE = RedfishRestExDxe.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + NetworkPkg/NetworkPkg.dec + RedfishPkg/RedfishPkg.dec + +[Sources] + ComponentName.c + RedfishRestExDriver.c + RedfishRestExDriver.h + RedfishRestExImpl.c + RedfishRestExProtocol.c + RedfishRestExInternal.h + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DevicePathLib + DpcLib + HttpLib + HttpIoLib + PrintLib + MemoryAllocationLib + NetLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + +[Protocols] + gEfiRestExServiceBindingProtocolGuid ## BY_START + gEfiRestExProtocolGuid ## BY_START + gEfiHttpServiceBindingProtocolGuid ## TO_START + gEfiHttpProtocolGuid ## TO_START + gEfiDevicePathProtocolGuid ## TO_START + +[Pcd] + gEfiRedfishPkgTokenSpaceGuid.PcdRedfishRestExServiceAccessModeInBand ## CONSUMES + +[UserExtensions.TianoCore."ExtraFiles"] + RedfishRestExDxeExtra.uni + diff --git a/RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.uni b/RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.uni new file mode 100644 index 0000000000..afa0c142a9 --- /dev/null +++ b/RedfishPkg/RedfishRestExDxe/RedfishRestExDxe.uni @@ -0,0 +1,16 @@ +// /** @file +// Redfish UEFI RESTEX DXE Driver. +// +// This driver provides Redfish UEFI RESTEX protocols. +// +// Copyright (c) 2019, Intel Corporation. All rights reserved.
+// (C) Copyright 2020 Hewlett Packard Enterprise Development LP
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "UEFI Redfish RESTEX service" + +#string STR_MODULE_DESCRIPTION #language en-US "This driver provides Redfish EFI RESTEX Protocol and Redfish EFI RESREX Service Binding Protocol." + diff --git a/RedfishPkg/RedfishRestExDxe/RedfishRestExDxeExtra.uni b/RedfishPkg/RedfishRestExDxe/RedfishRestExDxeExtra.uni new file mode 100644 index 0000000000..a8ecf8aede --- /dev/null +++ b/RedfishPkg/RedfishRestExDxe/RedfishRestExDxeExtra.uni @@ -0,0 +1,15 @@ +// /** @file +// RestExDxe Localized Strings and Content +// +// Copyright (c) 2019, Intel Corporation. All rights reserved.
+// (C) Copyright 2020 Hewlett Packard Enterprise Development LP
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"Redfish UEFI RESTEX DXE" + + diff --git a/RedfishPkg/RedfishRestExDxe/RedfishRestExImpl.c b/RedfishPkg/RedfishRestExDxe/RedfishRestExImpl.c new file mode 100644 index 0000000000..006b64adc0 --- /dev/null +++ b/RedfishPkg/RedfishRestExDxe/RedfishRestExImpl.c @@ -0,0 +1,157 @@ +/** @file + RestExDxe support functions implementation. + + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ (C) Copyright 2020 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include "RedfishRestExInternal.h" + +/** + Create a new TLS session becuase the previous on is closed. + status. + + @param[in] Instance Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @retval EFI_SUCCESS operation succeeded. + @retval EFI_ERROR Other errors. + +**/ +EFI_STATUS +ResetHttpTslSession ( + IN RESTEX_INSTANCE *Instance +) +{ + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "%a: TCP connection is finished. Could be TSL session closure, reset HTTP instance for the new TLS session.\n", __FUNCTION__)); + + Status = Instance->HttpIo.Http->Configure (Instance->HttpIo.Http, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Error to reset HTTP instance.\n", __FUNCTION__)); + return Status; + } + Status = Instance->HttpIo.Http->Configure(Instance->HttpIo.Http, &((EFI_REST_EX_HTTP_CONFIG_DATA *)Instance->ConfigData)->HttpConfigData); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Error to re-initiate HTTP instance.\n", __FUNCTION__)); + } + return Status; +} +/** + This function check + + @param[in] Instance Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[in] HttpIoReceiveStatus This is the status return from HttpIoRecvResponse + + @retval EFI_SUCCESS The payload receive from Redfish service in sucessfully. + @retval EFI_NOT_READY May need to resend the HTTP request. + @retval EFI_DEVICE_ERROR Something wrong and can't be resolved. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +RedfishCheckHttpReceiveStatus ( + IN RESTEX_INSTANCE *Instance, + IN EFI_STATUS HttpIoReceiveStatus + ) +{ + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + + if (!EFI_ERROR (HttpIoReceiveStatus)){ + ReturnStatus = EFI_SUCCESS; + } else if (EFI_ERROR (HttpIoReceiveStatus) && HttpIoReceiveStatus != EFI_CONNECTION_FIN) { + if ((Instance->Flags & RESTEX_INSTANCE_FLAGS_TCP_ERROR_RETRY) == 0) { + DEBUG ((DEBUG_ERROR, "%a: TCP error, reset HTTP session.\n", __FUNCTION__)); + Instance->Flags |= RESTEX_INSTANCE_FLAGS_TCP_ERROR_RETRY; + gBS->Stall (500); + Status = ResetHttpTslSession (Instance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Reset HTTP instance fail.\n", __FUNCTION__)); + ReturnStatus = EFI_DEVICE_ERROR; + } else { + return EFI_NOT_READY; + } + } else { + ReturnStatus = EFI_DEVICE_ERROR; + } + } else { + if (HttpIoReceiveStatus == EFI_CONNECTION_FIN) { + if ((Instance->Flags & RESTEX_INSTANCE_FLAGS_TLS_RETRY) != 0) { + DEBUG ((DEBUG_ERROR, "%a: REST_EX Send and receive fail even with a new TLS session.\n", __FUNCTION__)); + ReturnStatus = EFI_DEVICE_ERROR; + } + Instance->Flags |= RESTEX_INSTANCE_FLAGS_TLS_RETRY; + Status = ResetHttpTslSession (Instance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Reset HTTP instance fail.\n", __FUNCTION__)); + ReturnStatus = EFI_DEVICE_ERROR; + } + return EFI_NOT_READY; + } + } + // + // Clean TLS new session retry and error try flags. + // + Instance->Flags &= ~ (RESTEX_INSTANCE_FLAGS_TLS_RETRY | RESTEX_INSTANCE_FLAGS_TCP_ERROR_RETRY); + return ReturnStatus; +} + +/** + This function send the HTTP request without body to see + if the write to URL is permitted by Redfish service. This function + checks if the HTTP request has Content-length in HTTP header. If yes, + set HTTP body to NULL and then send to service. Check the HTTP status + for the firther actions. + + @param[in] This Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[in] RequestMessage Pointer to the HTTP request data for this resource + @param[in] PreservedRequestHeaders The pointer to save the request headers + @param[in] ItsWrite This is write method to URL. + + @retval EFI_INVALID_PARAMETER Improper given parameters. + @retval EFI_SUCCESS This HTTP request is free to send to Redfish service. + @retval EFI_OUT_OF_RESOURCES NOt enough memory to process. + @retval EFI_ACCESS_DENIED Not allowed to write to this URL. + + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +RedfishHttpAddExpectation ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_HTTP_MESSAGE *RequestMessage, + IN EFI_HTTP_HEADER **PreservedRequestHeaders, + IN BOOLEAN *ItsWrite + ) +{ + EFI_HTTP_HEADER *NewHeaders; + + if (This == NULL || RequestMessage == NULL) { + return EFI_INVALID_PARAMETER; + } + + *ItsWrite = FALSE; + if (PreservedRequestHeaders != NULL) { + *PreservedRequestHeaders = RequestMessage->Headers; + } + + if ((RequestMessage->Data.Request->Method != HttpMethodPut) && (RequestMessage->Data.Request->Method != HttpMethodPost) && + (RequestMessage->Data.Request->Method != HttpMethodPatch)) { + return EFI_SUCCESS; + } + *ItsWrite = TRUE; + + NewHeaders = AllocateZeroPool((RequestMessage->HeaderCount + 1) * sizeof(EFI_HTTP_HEADER)); + CopyMem ((VOID*)NewHeaders, (VOID *)RequestMessage->Headers, RequestMessage->HeaderCount * sizeof (EFI_HTTP_HEADER)); + HttpSetFieldNameAndValue (NewHeaders + RequestMessage->HeaderCount, HTTP_HEADER_EXPECT, HTTP_EXPECT_100_CONTINUE); + RequestMessage->HeaderCount ++; + RequestMessage->Headers = NewHeaders; + return EFI_SUCCESS; +} + diff --git a/RedfishPkg/RedfishRestExDxe/RedfishRestExInternal.h b/RedfishPkg/RedfishRestExDxe/RedfishRestExInternal.h new file mode 100644 index 0000000000..a75985928c --- /dev/null +++ b/RedfishPkg/RedfishRestExDxe/RedfishRestExInternal.h @@ -0,0 +1,611 @@ +/** @file + RedfishRestExDxe support functions definitions. + + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ (C) Copyright 2019-2020 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef EFI_REDFISH_RESTEX_INTERNAL_H_ +#define EFI_REDFISH_RESTEX_INTERNAL_H_ + +/// +/// Libraries classes +/// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/// +/// UEFI Driver Model Protocols +/// +#include +#include +#include + +#include "RedfishRestExDriver.h" + +/** + This function check + + @param[in] Instance Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[in] HttpReceiveEfiStatus This is the status return from HttpIoRecvResponse + + @retval EFI_SUCCESS The payload receive from Redfish service in sucessfully. + @retval EFI_NOT_READY May need to resend the HTTP request. + @retval EFI_DEVICE_ERROR Something wrong and can't be resolved. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +RedfishCheckHttpReceiveStatus ( + IN RESTEX_INSTANCE *Instance, + IN EFI_STATUS HttpIoReceiveStatus + ); + +/** + This function send the HTTP request without body to see + if the write to URL is permitted by Redfish service. This function + checks if the HTTP request has Content-length in HTTP header. If yes, + set HTTP body to NULL and then send to service. Check the HTTP status + for the firther actions. + + @param[in] This Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[in] RequestMessage Pointer to the HTTP request data for this resource + @param[in] PreservedRequestHeaders The pointer to save the request headers + @param[in] ItsWrite This is write method to URL. + + @retval EFI_INVALID_PARAMETER Improper given parameters. + @retval EFI_SUCCESS This HTTP request is free to send to Redfish service. + @retval EFI_OUT_OF_RESOURCES NOt enough memory to process. + @retval EFI_ACCESS_DENIED Not allowed to write to this URL. + + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +RedfishHttpAddExpectation ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_HTTP_MESSAGE *RequestMessage, + IN EFI_HTTP_HEADER **PreservedRequestHeaders, + IN BOOLEAN *ItsWrite + ); + +/** + Provides a simple HTTP-like interface to send and receive resources from a REST service. + + The SendReceive() function sends an HTTP request to this REST service, and returns a + response when the data is retrieved from the service. RequestMessage contains the HTTP + request to the REST resource identified by RequestMessage.Request.Url. The + ResponseMessage is the returned HTTP response for that request, including any HTTP + status. + + @param[in] This Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[in] RequestMessage Pointer to the HTTP request data for this resource + @param[out] ResponseMessage Pointer to the HTTP response data obtained for this requested. + + @retval EFI_SUCCESS operation succeeded. + @retval EFI_INVALID_PARAMETER This, RequestMessage, or ResponseMessage are NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExSendReceive ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_HTTP_MESSAGE *RequestMessage, + OUT EFI_HTTP_MESSAGE *ResponseMessage + ); + +/** + Obtain the current time from this REST service instance. + + The GetServiceTime() function is an optional interface to obtain the current time from + this REST service instance. If this REST service does not support to retrieve the time, + this function returns EFI_UNSUPPORTED. This function must returns EFI_UNSUPPORTED if + EFI_REST_EX_SERVICE_TYPE returned in EFI_REST_EX_SERVICE_INFO from GetService() is + EFI_REST_EX_SERVICE_UNSPECIFIC. + + @param[in] This Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[out] Time A pointer to storage to receive a snapshot of the current time of + the REST service. + + @retval EFI_SUCCESS operation succeeded. + @retval EFI_INVALID_PARAMETER This or Time are NULL. + @retval EFI_UNSUPPORTED The RESTful service does not support returning the time. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_NOT_READY The configuration of this instance is not set yet. Configure() must + be executed and returns successfully prior to invoke this function. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExGetServiceTime ( + IN EFI_REST_EX_PROTOCOL *This, + OUT EFI_TIME *Time + ); + +/** + This function returns the information of REST service provided by this EFI REST EX driver instance. + + The information such as the type of REST service and the access mode of REST EX driver instance + (In-band or Out-of-band) are described in EFI_REST_EX_SERVICE_INFO structure. For the vendor-specific + REST service, vendor-specific REST service information is returned in VendorSpecifcData. + REST EX driver designer is well know what REST service this REST EX driver instance intends to + communicate with. The designer also well know this driver instance is used to talk to BMC through + specific platform mechanism or talk to REST server through UEFI HTTP protocol. REST EX driver is + responsible to fill up the correct information in EFI_REST_EX_SERVICE_INFO. EFI_REST_EX_SERVICE_INFO + is referred by EFI REST clients to pickup the proper EFI REST EX driver instance to get and set resource. + GetService() is a basic and mandatory function which must be able to use even Configure() is not invoked + in previously. + + @param[in] This Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[out] RestExServiceInfo Pointer to receive a pointer to EFI_REST_EX_SERVICE_INFO structure. The + format of EFI_REST_EX_SERVICE_INFO is version controlled for the future + extension. The version of EFI_REST_EX_SERVICE_INFO structure is returned + in the header within this structure. EFI REST client refers to the correct + format of structure according to the version number. The pointer to + EFI_REST_EX_SERVICE_INFO is a memory block allocated by EFI REST EX driver + instance. That is caller's responsibility to free this memory when this + structure is no longer needed. Refer to Related Definitions below for the + definitions of EFI_REST_EX_SERVICE_INFO structure. + + @retval EFI_SUCCESS EFI_REST_EX_SERVICE_INFO is returned in RestExServiceInfo. This function + is not supported in this REST EX Protocol driver instance. + @retval EFI_UNSUPPORTED This function is not supported in this REST EX Protocol driver instance. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExGetService ( + IN EFI_REST_EX_PROTOCOL *This, + OUT EFI_REST_EX_SERVICE_INFO **RestExServiceInfo + ); + +/** + This function returns operational configuration of current EFI REST EX child instance. + + This function returns the current configuration of EFI REST EX child instance. The format of + operational configuration depends on the implementation of EFI REST EX driver instance. For + example, HTTP-aware EFI REST EX driver instance uses EFI HTTP protocol as the undying protocol + to communicate with REST service. In this case, the type of configuration is + EFI_REST_EX_CONFIG_TYPE_HTTP returned from GetService(). EFI_HTTP_CONFIG_DATA is used as EFI REST + EX configuration format and returned to EFI REST client. User has to type cast RestExConfigData + to EFI_HTTP_CONFIG_DATA. For those non HTTP-aware REST EX driver instances, the type of configuration + is EFI_REST_EX_CONFIG_TYPE_UNSPECIFIC returned from GetService(). In this case, the format of + returning data could be non industrial. Instead, the format of configuration data is system/platform + specific definition such as BMC mechanism used in EFI REST EX driver instance. EFI REST client and + EFI REST EX driver instance have to refer to the specific system /platform spec which is out of UEFI scope. + + @param[in] This This is the EFI_REST_EX_PROTOCOL instance. + @param[out] RestExConfigData Pointer to receive a pointer to EFI_REST_EX_CONFIG_DATA. + The memory allocated for configuration data should be freed + by caller. See Related Definitions for the details. + + @retval EFI_SUCCESS EFI_REST_EX_CONFIG_DATA is returned in successfully. + @retval EFI_UNSUPPORTED This function is not supported in this REST EX Protocol driver instance. + @retval EFI_NOT_READY The configuration of this instance is not set yet. Configure() must be + executed and returns successfully prior to invoke this function. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExGetModeData ( + IN EFI_REST_EX_PROTOCOL *This, + OUT EFI_REST_EX_CONFIG_DATA *RestExConfigData + ); + +/** + This function is used to configure EFI REST EX child instance. + + This function is used to configure the setting of underlying protocol of REST EX child + instance. The type of configuration is according to the implementation of EFI REST EX + driver instance. For example, HTTP-aware EFI REST EX driver instance uses EFI HTTP protocol + as the undying protocol to communicate with REST service. The type of configuration is + EFI_REST_EX_CONFIG_TYPE_HTTP and RestExConfigData is the same format with EFI_HTTP_CONFIG_DATA. + Akin to HTTP configuration, REST EX child instance can be configure to use different HTTP + local access point for the data transmission. Multiple REST clients may use different + configuration of HTTP to distinguish themselves, such as to use the different TCP port. + For those non HTTP-aware REST EX driver instance, the type of configuration is + EFI_REST_EX_CONFIG_TYPE_UNSPECIFIC. RestExConfigData refers to the non industrial standard. + Instead, the format of configuration data is system/platform specific definition such as BMC. + In this case, EFI REST client and EFI REST EX driver instance have to refer to the specific + system/platform spec which is out of the UEFI scope. Besides GetService()function, no other + EFI REST EX functions can be executed by this instance until Configure()is executed and returns + successfully. All other functions must returns EFI_NOT_READY if this instance is not configured + yet. Set RestExConfigData to NULL means to put EFI REST EX child instance into the unconfigured + state. + + @param[in] This This is the EFI_REST_EX_PROTOCOL instance. + @param[in] RestExConfigData Pointer to EFI_REST_EX_CONFIG_DATA. See Related Definitions in + GetModeData() protocol interface. + + @retval EFI_SUCCESS EFI_REST_EX_CONFIG_DATA is set in successfully. + @retval EFI_DEVICE_ERROR Configuration for this REST EX child instance is failed with the given + EFI_REST_EX_CONFIG_DATA. + @retval EFI_UNSUPPORTED This function is not supported in this REST EX Protocol driver instance. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExConfigure ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_REST_EX_CONFIG_DATA RestExConfigData + ); + +/** + This function sends REST request to REST service and signal caller's event asynchronously when + the final response is received by REST EX Protocol driver instance. + + The essential design of this function is to handle asynchronous send/receive implicitly according + to REST service asynchronous request mechanism. Caller will get the notification once the response + is returned from REST service. + + @param[in] This This is the EFI_REST_EX_PROTOCOL instance. + @param[in] RequestMessage This is the HTTP request message sent to REST service. Set RequestMessage + to NULL to cancel the previous asynchronous request associated with the + corresponding RestExToken. See descriptions for the details. + @param[in] RestExToken REST EX token which REST EX Protocol instance uses to notify REST client + the status of response of asynchronous REST request. See related definition + of EFI_REST_EX_TOKEN. + @param[in] TimeOutInMilliSeconds The pointer to the timeout in milliseconds which REST EX Protocol driver + instance refers as the duration to drop asynchronous REST request. NULL + pointer means no timeout for this REST request. REST EX Protocol driver + signals caller's event with EFI_STATUS set to EFI_TIMEOUT in RestExToken + if REST EX Protocol can't get the response from REST service within + TimeOutInMilliSeconds. + + @retval EFI_SUCCESS Asynchronous REST request is established. + @retval EFI_UNSUPPORTED This REST EX Protocol driver instance doesn't support asynchronous request. + @retval EFI_TIMEOUT Asynchronous REST request is not established and timeout is expired. + @retval EFI_ABORT Previous asynchronous REST request has been canceled. + @retval EFI_DEVICE_ERROR Otherwise, returns EFI_DEVICE_ERROR for other errors according to HTTP Status Code. + @retval EFI_NOT_READY The configuration of this instance is not set yet. Configure() must be executed + and returns successfully prior to invoke this function. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExAyncSendReceive ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_HTTP_MESSAGE *RequestMessage OPTIONAL, + IN EFI_REST_EX_TOKEN *RestExToken, + IN UINTN *TimeOutInMilliSeconds OPTIONAL + ); + +/** + This function sends REST request to a REST Event service and signals caller's event + token asynchronously when the URI resource change event is received by REST EX + Protocol driver instance. + + The essential design of this function is to monitor event implicitly according to + REST service event service mechanism. Caller will get the notification if certain + resource is changed. + + @param[in] This This is the EFI_REST_EX_PROTOCOL instance. + @param[in] RequestMessage This is the HTTP request message sent to REST service. Set RequestMessage + to NULL to cancel the previous event service associated with the corresponding + RestExToken. See descriptions for the details. + @param[in] RestExToken REST EX token which REST EX Protocol driver instance uses to notify REST client + the URI resource which monitored by REST client has been changed. See the related + definition of EFI_REST_EX_TOKEN in EFI_REST_EX_PROTOCOL.AsyncSendReceive(). + + @retval EFI_SUCCESS Asynchronous REST request is established. + @retval EFI_UNSUPPORTED This REST EX Protocol driver instance doesn't support asynchronous request. + @retval EFI_ABORT Previous asynchronous REST request has been canceled or event subscription has been + delete from service. + @retval EFI_DEVICE_ERROR Otherwise, returns EFI_DEVICE_ERROR for other errors according to HTTP Status Code. + @retval EFI_NOT_READY The configuration of this instance is not set yet. Configure() must be executed + and returns successfully prior to invoke this function. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExEventService ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_HTTP_MESSAGE *RequestMessage OPTIONAL, + IN EFI_REST_EX_TOKEN *RestExToken + ); +/** + Create a new TLS session becuase the previous on is closed. + status. + + @param[in] Instance Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @retval EFI_SUCCESS operation succeeded. + @retval EFI Errors Other errors. + +**/ +EFI_STATUS +ResetHttpTslSession ( + IN RESTEX_INSTANCE *Instance +); + + +/** + Callback function which provided by user to remove one node in NetDestroyLinkList process. + + @param[in] Entry The entry to be removed. + @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList. + + @retval EFI_SUCCESS The entry has been removed successfully. + @retval Others Fail to remove the entry. + +**/ +EFI_STATUS +EFIAPI +RestExDestroyChildEntryInHandleBuffer ( + IN LIST_ENTRY *Entry, + IN VOID *Context + ); + +/** + Destroy the RestEx instance and recycle the resources. + + @param[in] Instance The pointer to the RestEx instance. + +**/ +VOID +RestExDestroyInstance ( + IN RESTEX_INSTANCE *Instance + ); + +/** + Create the RestEx instance and initialize it. + + @param[in] Service The pointer to the RestEx service. + @param[out] Instance The pointer to the RestEx instance. + + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_SUCCESS The RestEx instance is created. + +**/ +EFI_STATUS +RestExCreateInstance ( + IN RESTEX_SERVICE *Service, + OUT RESTEX_INSTANCE **Instance + ); + + +/** + Release all the resource used the RestEx service binding instance. + + @param[in] RestExSb The RestEx service binding instance. + +**/ +VOID +RestExDestroyService ( + IN RESTEX_SERVICE *RestExSb + ); + +/** + Create then initialize a RestEx service binding instance. + + @param[in] Controller The controller to install the RestEx service + binding on. + @param[in] Image The driver binding image of the RestEx driver. + @param[out] Service The variable to receive the created service + binding instance. + + @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance. + @retval EFI_SUCCESS The service instance is created for the controller. + +**/ +EFI_STATUS +RestExCreateService ( + IN EFI_HANDLE Controller, + IN EFI_HANDLE Image, + OUT RESTEX_SERVICE **Service + ); + +/** + This is the declaration of an EFI image entry point. This entry point is + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including + both device drivers and bus drivers. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval Others An unexpected error occurred. +**/ +EFI_STATUS +EFIAPI +RedfishRestExDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Because ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +RedfishRestExDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); + +/** + Creates a child handle and installs a protocol. + + The CreateChild() function installs a protocol on ChildHandle. + If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle. + If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle. + + @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL, + then a new handle is created. If it is a pointer to an existing UEFI handle, + then the protocol is added to the existing UEFI handle. + + @retval EFI_SUCCES The protocol was added to ChildHandle. + @retval EFI_INVALID_PARAMETER ChildHandle is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create + the child + @retval other The child handle was not created + +**/ +EFI_STATUS +EFIAPI +RedfishRestExServiceBindingCreateChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE *ChildHandle + ); + +/** + Destroys a child handle with a protocol installed on it. + + The DestroyChild() function does the opposite of CreateChild(). It removes a protocol + that was installed by CreateChild() from ChildHandle. If the removed protocol is the + last protocol on ChildHandle, then ChildHandle is destroyed. + + @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param[in] ChildHandle Handle of the child to destroy + + @retval EFI_SUCCES The protocol was removed from ChildHandle. + @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed. + @retval EFI_INVALID_PARAMETER Child handle is NULL. + @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle + because its services are being used. + @retval other The child handle was not destroyed + +**/ +EFI_STATUS +EFIAPI +RedfishRestExServiceBindingDestroyChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE ChildHandle + ); +#endif diff --git a/RedfishPkg/RedfishRestExDxe/RedfishRestExProtocol.c b/RedfishPkg/RedfishRestExDxe/RedfishRestExProtocol.c new file mode 100644 index 0000000000..65a5fe3713 --- /dev/null +++ b/RedfishPkg/RedfishRestExDxe/RedfishRestExProtocol.c @@ -0,0 +1,735 @@ +/** @file + Implementation of Redfish EFI_REST_EX_PROTOCOL interfaces. + + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ (C) Copyright 2020 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include "RedfishRestExInternal.h" + +EFI_REST_EX_PROTOCOL mRedfishRestExProtocol = { + RedfishRestExSendReceive, + RedfishRestExGetServiceTime, + RedfishRestExGetService, + RedfishRestExGetModeData, + RedfishRestExConfigure, + RedfishRestExAyncSendReceive, + RedfishRestExEventService +}; + +/** + Provides a simple HTTP-like interface to send and receive resources from a REST service. + + The SendReceive() function sends an HTTP request to this REST service, and returns a + response when the data is retrieved from the service. RequestMessage contains the HTTP + request to the REST resource identified by RequestMessage.Request.Url. The + ResponseMessage is the returned HTTP response for that request, including any HTTP + status. + + @param[in] This Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[in] RequestMessage Pointer to the HTTP request data for this resource + @param[out] ResponseMessage Pointer to the HTTP response data obtained for this requested. + + @retval EFI_SUCCESS operation succeeded. + @retval EFI_INVALID_PARAMETER This, RequestMessage, or ResponseMessage are NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_ACCESS_DENIED HTTP method is not allowed on this URL. + @retval EFI_BAD_BUFFER_SIZE The payload is to large to be handled on server side. + @retval EFI_UNSUPPORTED Unsupported HTTP response. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExSendReceive ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_HTTP_MESSAGE *RequestMessage, + OUT EFI_HTTP_MESSAGE *ResponseMessage + ) +{ + EFI_STATUS Status; + RESTEX_INSTANCE *Instance; + HTTP_IO_RESPONSE_DATA *ResponseData; + UINTN TotalReceivedSize; + UINTN Index; + LIST_ENTRY *ChunkListLink; + HTTP_IO_CHUNKS *ThisChunk; + BOOLEAN CopyChunkData; + BOOLEAN MediaPresent; + EFI_HTTP_HEADER *PreservedRequestHeaders; + BOOLEAN ItsWrite; + BOOLEAN IsGetChunkedTransfer; + HTTP_IO_SEND_CHUNK_PROCESS SendChunkProcess; + HTTP_IO_SEND_NON_CHUNK_PROCESS SendNonChunkProcess; + EFI_HTTP_MESSAGE ChunkTransferRequestMessage; + + Status = EFI_SUCCESS; + ResponseData = NULL; + IsGetChunkedTransfer = FALSE; + SendChunkProcess = HttpIoSendChunkNone; + SendNonChunkProcess = HttpIoSendNonChunkNone; + + // + // Validate the parameters + // + if ((This == NULL) || (RequestMessage == NULL) || ResponseMessage == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = RESTEX_INSTANCE_FROM_THIS (This); + + // + // Check Media Status. + // + MediaPresent = TRUE; + NetLibDetectMedia (Instance->Service->ControllerHandle, &MediaPresent); + if (!MediaPresent) { + DEBUG ((DEBUG_INFO, "RedfishRestExSendReceive(): No MediaPresent.\n")); + return EFI_NO_MEDIA; + } + + DEBUG ((DEBUG_INFO, "\nRedfishRestExSendReceive():\n")); + DEBUG ((DEBUG_INFO, "*** Perform HTTP Request Method - %d, URL: %s\n", RequestMessage->Data.Request->Method, RequestMessage->Data.Request->Url)); + + // + // Add header "Expect" to server, only for URL write. + // + Status = RedfishHttpAddExpectation (This, RequestMessage, &PreservedRequestHeaders, &ItsWrite); + if (EFI_ERROR (Status)) { + return Status; + } + if (ItsWrite == TRUE) { + if (RequestMessage->BodyLength > HTTP_IO_MAX_SEND_PAYLOAD) { + // + // Send chunked transfer. + // + SendChunkProcess ++; + CopyMem ((VOID *)&ChunkTransferRequestMessage, (VOID *)RequestMessage, sizeof (EFI_HTTP_MESSAGE)); + } else { + SendNonChunkProcess ++; + } + } +ReSendRequest:; + // + // Send out the request to REST service. + // + if (ItsWrite == TRUE) { + // + // This is write to URI + // + if (SendChunkProcess > HttpIoSendChunkNone) { + // + // This is chunk transfer for writing large payload. + // Send request header first and then handle the + // following request message body using chunk transfer. + // + do { + Status = HttpIoSendChunkedTransfer( + &(Instance->HttpIo), + &SendChunkProcess, + &ChunkTransferRequestMessage + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } while (SendChunkProcess == HttpIoSendChunkContent || SendChunkProcess == HttpIoSendChunkEndChunk); + } else { + // + // This is the non-chunk transfer, send request header first and then + // handle the following request message body using chunk transfer. + // + Status = HttpIoSendRequest( + &(Instance->HttpIo), + (SendNonChunkProcess == HttpIoSendNonChunkContent)? NULL: RequestMessage->Data.Request, + (SendNonChunkProcess == HttpIoSendNonChunkContent)? 0: RequestMessage->HeaderCount, + (SendNonChunkProcess == HttpIoSendNonChunkContent)? NULL: RequestMessage->Headers, + (SendNonChunkProcess == HttpIoSendNonChunkHeaderZeroContent)? 0: RequestMessage->BodyLength, + (SendNonChunkProcess == HttpIoSendNonChunkHeaderZeroContent)? NULL: RequestMessage->Body + ); + } + } else { + // + // This is read from URI. + // + Status = HttpIoSendRequest( + &(Instance->HttpIo), + RequestMessage->Data.Request, + RequestMessage->HeaderCount, + RequestMessage->Headers, + RequestMessage->BodyLength, + RequestMessage->Body + ); + } + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // ResponseMessage->Data.Response is to indicate whether to receive the HTTP header or not. + // ResponseMessage->BodyLength/ResponseMessage->Body are to indicate whether to receive the response body or not. + // Clean the previous buffers and all of them will be allocated later according to the actual situation. + // + if (ResponseMessage->Data.Response != NULL) { + FreePool(ResponseMessage->Data.Response); + ResponseMessage->Data.Response = NULL; + } + + ResponseMessage->BodyLength = 0; + if (ResponseMessage->Body != NULL) { + FreePool(ResponseMessage->Body); + ResponseMessage->Body = NULL; + } + + // + // Use zero BodyLength to only receive the response headers. + // + ResponseData = AllocateZeroPool (sizeof(HTTP_IO_RESPONSE_DATA)); + if (ResponseData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + DEBUG ((DEBUG_INFO, "Receiving HTTP response and headers...\n")); + Status = RedfishCheckHttpReceiveStatus ( + Instance, + HttpIoRecvResponse ( + &(Instance->HttpIo), + TRUE, + ResponseData + ) + ); + if (Status == EFI_NOT_READY) { + goto ReSendRequest; + } else if (Status == EFI_DEVICE_ERROR) { + goto ON_EXIT; + } + // + // Restore the headers if it ever changed in RedfishHttpAddExpectation(). + // + if (RequestMessage->Headers != PreservedRequestHeaders) { + FreePool (RequestMessage->Headers); + RequestMessage->Headers = PreservedRequestHeaders; // Restore headers before we adding "Expect". + RequestMessage->HeaderCount --; // Minus one header count for "Expect". + } + + DEBUG ((DEBUG_INFO, "HTTP Response StatusCode - %d:", ResponseData->Response.StatusCode)); + if (ResponseData->Response.StatusCode == HTTP_STATUS_200_OK) { + DEBUG ((DEBUG_INFO, "HTTP_STATUS_200_OK\n")); + + if (SendChunkProcess == HttpIoSendChunkHeaderZeroContent) { + DEBUG ((DEBUG_INFO, "This is chunk transfer, start to send all chunks.", ResponseData->Response.StatusCode)); + SendChunkProcess ++; + goto ReSendRequest; + } + } else if (ResponseData->Response.StatusCode == HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE) { + DEBUG ((DEBUG_INFO, "HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE\n")); + + Status = EFI_BAD_BUFFER_SIZE; + goto ON_EXIT; + } else if (ResponseData->Response.StatusCode == HTTP_STATUS_405_METHOD_NOT_ALLOWED){ + DEBUG ((DEBUG_ERROR, "HTTP_STATUS_405_METHOD_NOT_ALLOWED\n")); + + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } else if (ResponseData->Response.StatusCode == HTTP_STATUS_400_BAD_REQUEST) { + DEBUG ((DEBUG_INFO, "HTTP_STATUS_400_BAD_REQUEST\n")); + if (SendChunkProcess == HttpIoSendChunkHeaderZeroContent) { + DEBUG ((DEBUG_INFO, "Bad request may caused by zero length chunk. Try to send all chunks...\n")); + SendChunkProcess ++; + goto ReSendRequest; + } + } else if (ResponseData->Response.StatusCode == HTTP_STATUS_100_CONTINUE) { + DEBUG ((DEBUG_INFO, "HTTP_STATUS_100_CONTINUE\n")); + if (SendChunkProcess == HttpIoSendChunkHeaderZeroContent) { + // + // We get HTTP_STATUS_100_CONTINUE to send the body using chunk transfer. + // + DEBUG ((DEBUG_INFO, "HTTP_STATUS_100_CONTINUE for chunk transfer...\n")); + SendChunkProcess ++; + goto ReSendRequest; + } + if (SendNonChunkProcess == HttpIoSendNonChunkHeaderZeroContent) { + DEBUG ((DEBUG_INFO, "HTTP_STATUS_100_CONTINUE for non chunk transfer...\n")); + SendNonChunkProcess ++; + goto ReSendRequest; + } + // + // It's the REST protocol's responsibility to handle the interim HTTP response (e.g. 100 Continue Informational), + // and return the final response content to the caller. + // + if (ResponseData->Headers != NULL && ResponseData->HeaderCount != 0) { + FreePool (ResponseData->Headers); + } + ZeroMem (ResponseData, sizeof(HTTP_IO_RESPONSE_DATA)); + Status = HttpIoRecvResponse ( + &(Instance->HttpIo), + TRUE, + ResponseData + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } else { + DEBUG ((DEBUG_ERROR, "This HTTP Status is not handled!\n")); + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } + + // + // Ready to return the StatusCode, Header info and BodyLength. + // + ResponseMessage->Data.Response = AllocateZeroPool (sizeof (EFI_HTTP_RESPONSE_DATA)); + if (ResponseMessage->Data.Response == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + ResponseMessage->Data.Response->StatusCode = ResponseData->Response.StatusCode; + ResponseMessage->HeaderCount = ResponseData->HeaderCount; + ResponseMessage->Headers = ResponseData->Headers; + + // + // Get response message body. + // + if (ResponseMessage->HeaderCount > 0) { + Status = HttpIoGetContentLength (ResponseMessage->HeaderCount, ResponseMessage->Headers, &ResponseMessage->BodyLength); + if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) { + goto ON_EXIT; + } + + if (Status == EFI_NOT_FOUND) { + ASSERT (ResponseMessage->BodyLength == 0); + } + + if (ResponseMessage->BodyLength == 0) { + // + // Check if Chunked Transfer Coding. + // + Status = HttpIoGetChunkedTransferContent ( + &(Instance->HttpIo), + ResponseMessage->HeaderCount, + ResponseMessage->Headers, + &ChunkListLink, + &ResponseMessage->BodyLength + ); + if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) { + goto ON_EXIT; + } + if (Status == EFI_SUCCESS && + ChunkListLink != NULL && + !IsListEmpty(ChunkListLink) && + ResponseMessage->BodyLength != 0) { + IsGetChunkedTransfer = TRUE; + // + // Copy data to Message body. + // + CopyChunkData = TRUE; + ResponseMessage->Body = AllocateZeroPool (ResponseMessage->BodyLength); + if (ResponseMessage->Body == NULL) { + Status = EFI_OUT_OF_RESOURCES; + CopyChunkData = FALSE; + } + Index = 0; + while (!IsListEmpty(ChunkListLink)) { + ThisChunk = (HTTP_IO_CHUNKS *)GetFirstNode (ChunkListLink); + if (CopyChunkData) { + CopyMem(((UINT8 *)ResponseMessage->Body + Index), (UINT8 *)ThisChunk->Data, ThisChunk->Length); + Index += ThisChunk->Length; + } + RemoveEntryList (&ThisChunk->NextChunk); + FreePool ((VOID *)ThisChunk->Data); + FreePool ((VOID *)ThisChunk); + }; + FreePool ((VOID *)ChunkListLink); + } + } + Status = EFI_SUCCESS; + } + + // + // Ready to return the Body from REST service if have any. + // + if (ResponseMessage->BodyLength > 0 && !IsGetChunkedTransfer) { + ResponseData->HeaderCount = 0; + ResponseData->Headers = NULL; + + ResponseMessage->Body = AllocateZeroPool (ResponseMessage->BodyLength); + if (ResponseMessage->Body == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Only receive the Body. + // + TotalReceivedSize = 0; + while (TotalReceivedSize < ResponseMessage->BodyLength) { + ResponseData->BodyLength = ResponseMessage->BodyLength - TotalReceivedSize; + ResponseData->Body = (CHAR8 *) ResponseMessage->Body + TotalReceivedSize; + Status = HttpIoRecvResponse ( + &(Instance->HttpIo), + FALSE, + ResponseData + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + TotalReceivedSize += ResponseData->BodyLength; + } + DEBUG ((DEBUG_INFO, "Total of lengh of Response :%d\n", TotalReceivedSize)); + } + DEBUG ((DEBUG_INFO, "RedfishRestExSendReceive()- EFI_STATUS: %r\n", Status)); + +ON_EXIT: + + if (ResponseData != NULL) { + FreePool (ResponseData); + } + + if (EFI_ERROR (Status)) { + if (ResponseMessage->Data.Response != NULL) { + FreePool (ResponseMessage->Data.Response); + ResponseMessage->Data.Response = NULL; + } + + if (ResponseMessage->Body != NULL) { + FreePool (ResponseMessage->Body); + ResponseMessage->Body = NULL; + } + } + return Status; +} + +/** + Obtain the current time from this REST service instance. + + The GetServiceTime() function is an optional interface to obtain the current time from + this REST service instance. If this REST service does not support to retrieve the time, + this function returns EFI_UNSUPPORTED. This function must returns EFI_UNSUPPORTED if + EFI_REST_EX_SERVICE_TYPE returned in EFI_REST_EX_SERVICE_INFO from GetService() is + EFI_REST_EX_SERVICE_UNSPECIFIC. + + @param[in] This Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[out] Time A pointer to storage to receive a snapshot of the current time of + the REST service. + + @retval EFI_SUCCESS operation succeeded. + @retval EFI_INVALID_PARAMETER This or Time are NULL. + @retval EFI_UNSUPPORTED The RESTful service does not support returning the time. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_NOT_READY The configuration of this instance is not set yet. Configure() must + be executed and returns successfully prior to invoke this function. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExGetServiceTime ( + IN EFI_REST_EX_PROTOCOL *This, + OUT EFI_TIME *Time + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This function returns the information of REST service provided by this EFI REST EX driver instance. + + The information such as the type of REST service and the access mode of REST EX driver instance + (In-band or Out-of-band) are described in EFI_REST_EX_SERVICE_INFO structure. For the vendor-specific + REST service, vendor-specific REST service information is returned in VendorSpecifcData. + REST EX driver designer is well know what REST service this REST EX driver instance intends to + communicate with. The designer also well know this driver instance is used to talk to BMC through + specific platform mechanism or talk to REST server through UEFI HTTP protocol. REST EX driver is + responsible to fill up the correct information in EFI_REST_EX_SERVICE_INFO. EFI_REST_EX_SERVICE_INFO + is referred by EFI REST clients to pickup the proper EFI REST EX driver instance to get and set resource. + GetService() is a basic and mandatory function which must be able to use even Configure() is not invoked + in previously. + + @param[in] This Pointer to EFI_REST_EX_PROTOCOL instance for a particular + REST service. + @param[out] RestExServiceInfo Pointer to receive a pointer to EFI_REST_EX_SERVICE_INFO structure. The + format of EFI_REST_EX_SERVICE_INFO is version controlled for the future + extension. The version of EFI_REST_EX_SERVICE_INFO structure is returned + in the header within this structure. EFI REST client refers to the correct + format of structure according to the version number. The pointer to + EFI_REST_EX_SERVICE_INFO is a memory block allocated by EFI REST EX driver + instance. That is caller's responsibility to free this memory when this + structure is no longer needed. Refer to Related Definitions below for the + definitions of EFI_REST_EX_SERVICE_INFO structure. + + @retval EFI_SUCCESS EFI_REST_EX_SERVICE_INFO is returned in RestExServiceInfo. This function + is not supported in this REST EX Protocol driver instance. + @retval EFI_UNSUPPORTED This function is not supported in this REST EX Protocol driver instance. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExGetService ( + IN EFI_REST_EX_PROTOCOL *This, + OUT EFI_REST_EX_SERVICE_INFO **RestExServiceInfo + ) +{ + EFI_TPL OldTpl; + RESTEX_INSTANCE *Instance; + EFI_REST_EX_SERVICE_INFO *ServiceInfo; + + ServiceInfo = NULL; + + if (This == NULL || RestExServiceInfo == NULL) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance = RESTEX_INSTANCE_FROM_THIS (This); + + ServiceInfo = AllocateZeroPool (sizeof (EFI_REST_EX_SERVICE_INFO)); + if (ServiceInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (ServiceInfo, &(Instance->Service->RestExServiceInfo), sizeof (EFI_REST_EX_SERVICE_INFO)); + + *RestExServiceInfo = ServiceInfo; + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; +} + +/** + This function returns operational configuration of current EFI REST EX child instance. + + This function returns the current configuration of EFI REST EX child instance. The format of + operational configuration depends on the implementation of EFI REST EX driver instance. For + example, HTTP-aware EFI REST EX driver instance uses EFI HTTP protocol as the undying protocol + to communicate with REST service. In this case, the type of configuration is + EFI_REST_EX_CONFIG_TYPE_HTTP returned from GetService(). EFI_HTTP_CONFIG_DATA is used as EFI REST + EX configuration format and returned to EFI REST client. User has to type cast RestExConfigData + to EFI_HTTP_CONFIG_DATA. For those non HTTP-aware REST EX driver instances, the type of configuration + is EFI_REST_EX_CONFIG_TYPE_UNSPECIFIC returned from GetService(). In this case, the format of + returning data could be non industrial. Instead, the format of configuration data is system/platform + specific definition such as BMC mechanism used in EFI REST EX driver instance. EFI REST client and + EFI REST EX driver instance have to refer to the specific system /platform spec which is out of UEFI scope. + + @param[in] This This is the EFI_REST_EX_PROTOCOL instance. + @param[out] RestExConfigData Pointer to receive a pointer to EFI_REST_EX_CONFIG_DATA. + The memory allocated for configuration data should be freed + by caller. See Related Definitions for the details. + + @retval EFI_SUCCESS EFI_REST_EX_CONFIG_DATA is returned in successfully. + @retval EFI_UNSUPPORTED This function is not supported in this REST EX Protocol driver instance. + @retval EFI_NOT_READY The configuration of this instance is not set yet. Configure() must be + executed and returns successfully prior to invoke this function. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExGetModeData ( + IN EFI_REST_EX_PROTOCOL *This, + OUT EFI_REST_EX_CONFIG_DATA *RestExConfigData + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This function is used to configure EFI REST EX child instance. + + This function is used to configure the setting of underlying protocol of REST EX child + instance. The type of configuration is according to the implementation of EFI REST EX + driver instance. For example, HTTP-aware EFI REST EX driver instance uses EFI HTTP protocol + as the undying protocol to communicate with REST service. The type of configuration is + EFI_REST_EX_CONFIG_TYPE_HTTP and RestExConfigData is the same format with EFI_HTTP_CONFIG_DATA. + Akin to HTTP configuration, REST EX child instance can be configure to use different HTTP + local access point for the data transmission. Multiple REST clients may use different + configuration of HTTP to distinguish themselves, such as to use the different TCP port. + For those non HTTP-aware REST EX driver instance, the type of configuration is + EFI_REST_EX_CONFIG_TYPE_UNSPECIFIC. RestExConfigData refers to the non industrial standard. + Instead, the format of configuration data is system/platform specific definition such as BMC. + In this case, EFI REST client and EFI REST EX driver instance have to refer to the specific + system/platform spec which is out of the UEFI scope. Besides GetService()function, no other + EFI REST EX functions can be executed by this instance until Configure()is executed and returns + successfully. All other functions must returns EFI_NOT_READY if this instance is not configured + yet. Set RestExConfigData to NULL means to put EFI REST EX child instance into the unconfigured + state. + + @param[in] This This is the EFI_REST_EX_PROTOCOL instance. + @param[in] RestExConfigData Pointer to EFI_REST_EX_CONFIG_DATA. See Related Definitions in + GetModeData() protocol interface. + + @retval EFI_SUCCESS EFI_REST_EX_CONFIG_DATA is set in successfully. + @retval EFI_DEVICE_ERROR Configuration for this REST EX child instance is failed with the given + EFI_REST_EX_CONFIG_DATA. + @retval EFI_UNSUPPORTED This function is not supported in this REST EX Protocol driver instance. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExConfigure ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_REST_EX_CONFIG_DATA RestExConfigData + ) +{ + EFI_STATUS Status; + EFI_TPL OldTpl; + RESTEX_INSTANCE *Instance; + + EFI_HTTP_CONFIG_DATA *HttpConfigData; + + Status = EFI_SUCCESS; + HttpConfigData = NULL; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance = RESTEX_INSTANCE_FROM_THIS (This); + + if (RestExConfigData == NULL) { + // + // Set RestExConfigData to NULL means to put EFI REST EX child instance into the unconfigured state. + // + HttpIoDestroyIo (&(Instance->HttpIo)); + + if (Instance->ConfigData != NULL) { + if (((EFI_REST_EX_HTTP_CONFIG_DATA *)Instance->ConfigData)->HttpConfigData.AccessPoint.IPv4Node != NULL) { + FreePool(((EFI_REST_EX_HTTP_CONFIG_DATA *)Instance->ConfigData)->HttpConfigData.AccessPoint.IPv4Node); + } + FreePool(Instance->ConfigData); + Instance->ConfigData = NULL; + } + + Instance->State = RESTEX_STATE_UNCONFIGED; + } else { + HttpConfigData = &((EFI_REST_EX_HTTP_CONFIG_DATA *)RestExConfigData)->HttpConfigData; + Status = Instance->HttpIo.Http->Configure (Instance->HttpIo.Http, HttpConfigData); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + Instance->HttpIo.Timeout = ((EFI_REST_EX_HTTP_CONFIG_DATA *)RestExConfigData)->SendReceiveTimeout; + + Instance->ConfigData = AllocateZeroPool (sizeof (EFI_REST_EX_HTTP_CONFIG_DATA)); + if (Instance->ConfigData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + CopyMem (Instance->ConfigData, RestExConfigData, sizeof (EFI_REST_EX_HTTP_CONFIG_DATA)); + if (HttpConfigData->LocalAddressIsIPv6 == TRUE) { + ((EFI_REST_EX_HTTP_CONFIG_DATA *)Instance->ConfigData)->HttpConfigData.AccessPoint.IPv6Node = AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT)); + if (((EFI_REST_EX_HTTP_CONFIG_DATA *)Instance->ConfigData)->HttpConfigData.AccessPoint.IPv6Node == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + CopyMem ( + ((EFI_REST_EX_HTTP_CONFIG_DATA *)Instance->ConfigData)->HttpConfigData.AccessPoint.IPv6Node, + HttpConfigData->AccessPoint.IPv6Node, + sizeof (EFI_HTTPv6_ACCESS_POINT) + ); + } else { + ((EFI_REST_EX_HTTP_CONFIG_DATA *)Instance->ConfigData)->HttpConfigData.AccessPoint.IPv4Node = AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT)); + if (((EFI_REST_EX_HTTP_CONFIG_DATA *)Instance->ConfigData)->HttpConfigData.AccessPoint.IPv4Node == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + CopyMem ( + ((EFI_REST_EX_HTTP_CONFIG_DATA *)Instance->ConfigData)->HttpConfigData.AccessPoint.IPv4Node, + HttpConfigData->AccessPoint.IPv4Node, + sizeof (EFI_HTTPv4_ACCESS_POINT) + ); + } + Instance->State = RESTEX_STATE_CONFIGED; + } + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + This function sends REST request to REST service and signal caller's event asynchronously when + the final response is received by REST EX Protocol driver instance. + + The essential design of this function is to handle asynchronous send/receive implicitly according + to REST service asynchronous request mechanism. Caller will get the notification once the response + is returned from REST service. + + @param[in] This This is the EFI_REST_EX_PROTOCOL instance. + @param[in] RequestMessage This is the HTTP request message sent to REST service. Set RequestMessage + to NULL to cancel the previous asynchronous request associated with the + corresponding RestExToken. See descriptions for the details. + @param[in] RestExToken REST EX token which REST EX Protocol instance uses to notify REST client + the status of response of asynchronous REST request. See related definition + of EFI_REST_EX_TOKEN. + @param[in] TimeOutInMilliSeconds The pointer to the timeout in milliseconds which REST EX Protocol driver + instance refers as the duration to drop asynchronous REST request. NULL + pointer means no timeout for this REST request. REST EX Protocol driver + signals caller's event with EFI_STATUS set to EFI_TIMEOUT in RestExToken + if REST EX Protocol can't get the response from REST service within + TimeOutInMilliSeconds. + + @retval EFI_SUCCESS Asynchronous REST request is established. + @retval EFI_UNSUPPORTED This REST EX Protocol driver instance doesn't support asynchronous request. + @retval EFI_TIMEOUT Asynchronous REST request is not established and timeout is expired. + @retval EFI_ABORT Previous asynchronous REST request has been canceled. + @retval EFI_DEVICE_ERROR Otherwise, returns EFI_DEVICE_ERROR for other errors according to HTTP Status Code. + @retval EFI_NOT_READY The configuration of this instance is not set yet. Configure() must be executed + and returns successfully prior to invoke this function. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExAyncSendReceive ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_HTTP_MESSAGE *RequestMessage OPTIONAL, + IN EFI_REST_EX_TOKEN *RestExToken, + IN UINTN *TimeOutInMilliSeconds OPTIONAL + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This function sends REST request to a REST Event service and signals caller's event + token asynchronously when the URI resource change event is received by REST EX + Protocol driver instance. + + The essential design of this function is to monitor event implicitly according to + REST service event service mechanism. Caller will get the notification if certain + resource is changed. + + @param[in] This This is the EFI_REST_EX_PROTOCOL instance. + @param[in] RequestMessage This is the HTTP request message sent to REST service. Set RequestMessage + to NULL to cancel the previous event service associated with the corresponding + RestExToken. See descriptions for the details. + @param[in] RestExToken REST EX token which REST EX Protocol driver instance uses to notify REST client + the URI resource which monitored by REST client has been changed. See the related + definition of EFI_REST_EX_TOKEN in EFI_REST_EX_PROTOCOL.AsyncSendReceive(). + + @retval EFI_SUCCESS Asynchronous REST request is established. + @retval EFI_UNSUPPORTED This REST EX Protocol driver instance doesn't support asynchronous request. + @retval EFI_ABORT Previous asynchronous REST request has been canceled or event subscription has been + delete from service. + @retval EFI_DEVICE_ERROR Otherwise, returns EFI_DEVICE_ERROR for other errors according to HTTP Status Code. + @retval EFI_NOT_READY The configuration of this instance is not set yet. Configure() must be executed + and returns successfully prior to invoke this function. + +**/ +EFI_STATUS +EFIAPI +RedfishRestExEventService ( + IN EFI_REST_EX_PROTOCOL *This, + IN EFI_HTTP_MESSAGE *RequestMessage OPTIONAL, + IN EFI_REST_EX_TOKEN *RestExToken + ) +{ + return EFI_UNSUPPORTED; +} + -- 2.39.2