summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb')
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch695
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch74
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch67
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch135
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-Log-RedFish-event-for-Invalid-login-attempt.patch67
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-Add-UART-routing-logic-into-host-console-connection-.patch59
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-recommended-fixes-by-crypto-review-team.patch75
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-state-sensor-messages-to-the-registry.patch98
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-Fix-bmcweb-crashes-if-socket-directory-not-present.patch44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-msg-registry-for-subscription-related-actions.patch81
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-bmcweb-Add-BMC-Time-update-log-to-the-registry.patch77
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-Add-generic-message-PropertySizeExceeded.patch118
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0001-Define-Redfish-interface-Registries-Bios.patch848
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0002-BaseBiosTable-Add-support-for-PATCH-operation.patch152
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0003-Add-support-to-ResetBios-action.patch61
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0004-Add-support-to-ChangePassword-action.patch139
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0005-Fix-remove-bios-user-pwd-change-option-via-Redfish.patch44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket9
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-EventService-Fix-retry-handling-for-http-client.patch547
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch402
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch478
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch666
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch292
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0007-EventService-Log-events-for-subscription-actions.patch132
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch85
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch491
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch294
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Revert-Remove-LogService-from-TelemetryService.patch26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-event-service-fix-added-Context-field-to-response.patch29
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0001-Revert-Disable-nbd-proxy-from-the-build.patch50
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0002-bmcweb-handle-device-or-resource-busy-exception.patch219
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0003-Add-ConnectedVia-property-to-virtual-media-item-temp.patch28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0004-Invalid-status-code-from-InsertMedia-REST-methods.patch185
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0005-Set-Inserted-redfish-property-for-not-inserted-resou.patch43
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0006-Bmcweb-handle-permission-denied-exception.patch47
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0007-Fix-unmounting-image-in-proxy-mode.patch35
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0008-Fix-VM-NBDPROXY-build-issue-with-AsyncResp.patch37
39 files changed, 6963 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch
new file mode 100755
index 000000000..a76990262
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch
@@ -0,0 +1,695 @@
+From d5f2e8b00bc5f8a727a1ef678941c4993c3ea7a6 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Date: Wed, 18 Nov 2020 17:14:41 +0530
+Subject: [PATCH] Firmware update configuration changes
+
+This commit will provide user to PATCH the below firmware update
+attributes before uploding the firmware image.
+
+1. This will have PATCH support for 'HttpPushUriTargets' and
+'HttpPushUriTargetsBusy' attributes. These attributes enables
+'HttpPushUri' to distinguish between the firmware update targets.
+
+2. ApplyOptions are used to specify firmware update specific options
+such as ClearConfig which is used while activating the updated
+firmware. This setting is maintained in a local static variable
+when set using PATCH method. Its used in activate image as input
+parameter. This attribute is added as Oem as the default
+UpdateService interface doesn't specify any relevant or appropriate
+attribute for this.
+
+Tested:
+ - GET on "/redfish/v1/UpdateService", got below response
+.........
+ "HttpPushUriTargets": [],
+ "HttpPushUriTargetsBusy": false
+........
+
+ - PATCH on "/redfish/v1/UpdateService" and works fine.
+{
+ "HttpPushUriTargets": ["bmc_recovery"],
+ "HttpPushUriTargetsBusy": true
+}
+
+ - Did Firmware update and verified end to end functionality
+ for both bmc active and backup images.
+
+ - Tested setting ClearConfig to true or false using PATCH
+ method.
+
+ - Successfully ran redfish validater with no new errors.
+
+Change-Id: I44e1743fd76aa37c7b8affa49a3e05f808187037
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Signed-off-by: Helen Huang <he.huang@intel.com>
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+---
+ redfish-core/lib/update_service.hpp | 338 ++++++++++++++++--
+ static/redfish/v1/$metadata/index.xml | 3 +
+ .../JsonSchemas/OemUpdateService/index.json | 69 ++++
+ .../redfish/v1/schema/OemUpdateService_v1.xml | 40 +++
+ 4 files changed, 421 insertions(+), 29 deletions(-)
+ create mode 100644 static/redfish/v1/JsonSchemas/OemUpdateService/index.json
+ create mode 100644 static/redfish/v1/schema/OemUpdateService_v1.xml
+
+diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
+index ca1234f..0a9f81a 100644
+--- a/redfish-core/lib/update_service.hpp
++++ b/redfish-core/lib/update_service.hpp
+@@ -32,6 +32,17 @@ static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateErrorMatcher;
+ static bool fwUpdateInProgress = false;
+ // Timer for software available
+ static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
++static constexpr const char* versionIntf =
++ "xyz.openbmc_project.Software.Version";
++static constexpr const char* activationIntf =
++ "xyz.openbmc_project.Software.Activation";
++static constexpr const char* reqActivationPropName = "RequestedActivation";
++static constexpr const char* reqActivationsActive =
++ "xyz.openbmc_project.Software.Activation.RequestedActivations.Active";
++static constexpr const char* reqActivationsStandBySpare =
++ "xyz.openbmc_project.Software.Activation.RequestedActivations.StandbySpare";
++static constexpr const char* activationsStandBySpare =
++ "xyz.openbmc_project.Software.Activation.Activations.StandbySpare";
+
+ static void cleanUp()
+ {
+@@ -40,28 +51,120 @@ static void cleanUp()
+ fwUpdateErrorMatcher = nullptr;
+ }
+ static void activateImage(const std::string& objPath,
+- const std::string& service)
++ const std::string& service,
++ const std::vector<std::string>& imgUriTargets)
+ {
+ BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
++ // If targets is empty, it will apply to the active.
++ if (imgUriTargets.size() == 0)
++ {
++ crow::connections::systemBus->async_method_call(
++ [](const boost::system::error_code error_code) {
++ if (error_code)
++ {
++ BMCWEB_LOG_DEBUG
++ << "RequestedActivation failed: error_code = "
++ << error_code;
++ BMCWEB_LOG_DEBUG << "error msg = " << error_code.message();
++ }
++ },
++ service, objPath, "org.freedesktop.DBus.Properties", "Set",
++ activationIntf, reqActivationPropName,
++ std::variant<std::string>(reqActivationsActive));
++ return;
++ }
++
++ // TODO: Now we support only one target becuase software-manager
++ // code support one activation per object. It will be enhanced
++ // to multiple targets for single image in future. For now,
++ // consider first target alone.
+ crow::connections::systemBus->async_method_call(
+- [](const boost::system::error_code errorCode) {
+- if (errorCode)
++ [objPath, service, imgTarget{imgUriTargets[0]}](
++ const boost::system::error_code ec,
++ const crow::openbmc_mapper::GetSubTreeType& subtree) {
++ if (ec || !subtree.size())
+ {
+- BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
+- BMCWEB_LOG_DEBUG << "error msg = " << errorCode.message();
++ return;
++ }
++
++ for (const auto& [invObjPath, invDict] : subtree)
++ {
++ std::size_t idPos = invObjPath.rfind("/");
++ if ((idPos == std::string::npos) ||
++ ((idPos + 1) >= invObjPath.size()))
++ {
++ BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
++ return;
++ }
++ std::string swId = invObjPath.substr(idPos + 1);
++
++ if (swId != imgTarget)
++ {
++ continue;
++ }
++
++ if (invDict.size() < 1)
++ {
++ continue;
++ }
++ BMCWEB_LOG_DEBUG << "Image target matched with object "
++ << invObjPath;
++ crow::connections::systemBus->async_method_call(
++ [objPath,
++ service](const boost::system::error_code error_code,
++ const std::variant<std::string> value) {
++ if (error_code)
++ {
++ BMCWEB_LOG_DEBUG
++ << "Error in querying activation value";
++ // not all fwtypes are updateable,
++ // this is ok
++ return;
++ }
++ std::string activationValue =
++ std::get<std::string>(value);
++ BMCWEB_LOG_DEBUG << "Activation Value: "
++ << activationValue;
++ std::string reqActivation = reqActivationsActive;
++ if (activationValue == activationsStandBySpare)
++ {
++ reqActivation = reqActivationsStandBySpare;
++ }
++ BMCWEB_LOG_DEBUG
++ << "Setting RequestedActivation value as "
++ << reqActivation << " for " << service << " "
++ << objPath;
++ crow::connections::systemBus->async_method_call(
++ [](const boost::system::error_code error_code) {
++ if (error_code)
++ {
++ BMCWEB_LOG_DEBUG
++ << "RequestedActivation failed: ec = "
++ << error_code;
++ }
++ return;
++ },
++ service, objPath, "org.freedesktop.DBus.Properties",
++ "Set", activationIntf, reqActivationPropName,
++ std::variant<std::string>(reqActivation));
++ },
++ invDict[0].first,
++ "/xyz/openbmc_project/software/" + imgTarget,
++ "org.freedesktop.DBus.Properties", "Get", activationIntf,
++ "Activation");
+ }
+ },
+- service, objPath, "org.freedesktop.DBus.Properties", "Set",
+- "xyz.openbmc_project.Software.Activation", "RequestedActivation",
+- std::variant<std::string>(
+- "xyz.openbmc_project.Software.Activation.RequestedActivations."
+- "Active"));
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
++ static_cast<int32_t>(0), std::array<const char*, 1>{versionIntf});
+ }
+
+ // Note that asyncResp can be either a valid pointer or nullptr. If nullptr
+ // then no asyncResp updates will occur
+ static void
+ softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const std::vector<std::string> imgUriTargets,
+ sdbusplus::message::message& m,
+ const crow::Request& req)
+ {
+@@ -74,22 +177,24 @@ static void
+
+ m.read(objPath, interfacesProperties);
+
+- BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
++ BMCWEB_LOG_DEBUG << "Software Interface Added. obj path = " << objPath.str;
+ for (auto& interface : interfacesProperties)
+ {
+ BMCWEB_LOG_DEBUG << "interface = " << interface.first;
+
+- if (interface.first == "xyz.openbmc_project.Software.Activation")
++ if (interface.first == activationIntf)
+ {
+ // Retrieve service and activate
+ crow::connections::systemBus->async_method_call(
+- [objPath, asyncResp,
++ [objPath, asyncResp, imgTargets{imgUriTargets},
+ req](const boost::system::error_code errorCode,
+ const std::vector<std::pair<
+ std::string, std::vector<std::string>>>& objInfo) {
+ if (errorCode)
+ {
+- BMCWEB_LOG_DEBUG << "error_code = " << errorCode;
++ BMCWEB_LOG_DEBUG
++ << "GetSoftwareObject path failed: error_code = "
++ << errorCode;
+ BMCWEB_LOG_DEBUG << "error msg = "
+ << errorCode.message();
+ if (asyncResp)
+@@ -116,7 +221,7 @@ static void
+ // is added
+ fwAvailableTimer = nullptr;
+
+- activateImage(objPath.str, objInfo[0].first);
++ activateImage(objPath.str, objInfo[0].first, imgTargets);
+ if (asyncResp)
+ {
+ std::shared_ptr<task::TaskData> task =
+@@ -248,8 +353,7 @@ static void
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str,
+- std::array<const char*, 1>{
+- "xyz.openbmc_project.Software.Activation"});
++ std::array<const char*, 1>{activationIntf});
+ }
+ }
+ }
+@@ -259,7 +363,7 @@ static void
+ static void monitorForSoftwareAvailable(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const crow::Request& req, const std::string& url,
+- int timeoutTimeSeconds = 10)
++ const std::vector<std::string>& imgUriTargets, int timeoutTimeSeconds = 10)
+ {
+ // Only allow one FW update at a time
+ if (fwUpdateInProgress != false)
+@@ -299,9 +403,10 @@ static void monitorForSoftwareAvailable(
+ }
+ });
+
+- auto callback = [asyncResp, req](sdbusplus::message::message& m) {
++ auto callback = [asyncResp, imgTargets{imgUriTargets},
++ req](sdbusplus::message::message& m) {
+ BMCWEB_LOG_DEBUG << "Match fired";
+- softwareInterfaceAdded(asyncResp, m, req);
++ softwareInterfaceAdded(asyncResp, imgTargets, m, req);
+ };
+
+ fwUpdateInProgress = true;
+@@ -477,12 +582,15 @@ class UpdateServiceActionsSimpleUpdate : public Node
+ std::string fwFile = imageURI.substr(separator + 1);
+ BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
+
++ // We will pass empty targets and its handled in activation.
++ std::vector<std::string> httpUriTargets;
++
+ // Setup callback for when new software detected
+ // Give TFTP 10 minutes to complete
+ monitorForSoftwareAvailable(
+ asyncResp, req,
+ "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
+- 600);
++ httpUriTargets, 600);
+
+ // TFTP can take up to 10 minutes depending on image size and
+ // connection speed. Return to caller as soon as the TFTP operation
+@@ -516,7 +624,8 @@ class UpdateServiceActionsSimpleUpdate : public Node
+ class UpdateService : public Node
+ {
+ public:
+- UpdateService(App& app) : Node(app, "/redfish/v1/UpdateService/")
++ UpdateService(App& app) :
++ Node(app, "/redfish/v1/UpdateService/"), httpPushUriTargetBusy(false)
+ {
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+@@ -528,6 +637,8 @@ class UpdateService : public Node
+ }
+
+ private:
++ std::vector<std::string> httpPushUriTargets;
++ bool httpPushUriTargetBusy;
+ void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const crow::Request&, const std::vector<std::string>&) override
+ {
+@@ -538,6 +649,9 @@ class UpdateService : public Node
+ asyncResp->res.jsonValue["Description"] = "Service for Software Update";
+ asyncResp->res.jsonValue["Name"] = "Update Service";
+ asyncResp->res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService";
++ asyncResp->res.jsonValue["HttpPushUriTargets"] = httpPushUriTargets;
++ asyncResp->res.jsonValue["HttpPushUriTargetsBusy"] =
++ httpPushUriTargetBusy;
+ // UpdateService cannot be disabled
+ asyncResp->res.jsonValue["ServiceEnabled"] = true;
+ asyncResp->res.jsonValue["FirmwareInventory"] = {
+@@ -587,6 +701,32 @@ class UpdateService : public Node
+ "/xyz/openbmc_project/software/apply_time",
+ "org.freedesktop.DBus.Properties", "Get",
+ "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime");
++
++ // Get the ApplyOptions value
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const std::variant<bool> applyOption) {
++ if (ec)
++ {
++ BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ const bool* b = std::get_if<bool>(&applyOption);
++
++ if (b)
++ {
++ asyncResp->res
++ .jsonValue["Oem"]["ApplyOptions"]["@odata.type"] =
++ "#OemUpdateService.ApplyOptions";
++ asyncResp->res
++ .jsonValue["Oem"]["ApplyOptions"]["ClearConfig"] = *b;
++ }
++ },
++ "xyz.openbmc_project.Software.BMC.Updater",
++ "/xyz/openbmc_project/software", "org.freedesktop.DBus.Properties",
++ "Get", "xyz.openbmc_project.Software.ApplyOptions", "ClearConfig");
+ }
+
+ void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+@@ -596,12 +736,61 @@ class UpdateService : public Node
+ BMCWEB_LOG_DEBUG << "doPatch...";
+
+ std::optional<nlohmann::json> pushUriOptions;
++ std::optional<std::vector<std::string>> imgTargets;
++ std::optional<bool> imgTargetBusy;
++ std::optional<nlohmann::json> oemProps;
++
+ if (!json_util::readJson(req, asyncResp->res, "HttpPushUriOptions",
+- pushUriOptions))
++ pushUriOptions, "HttpPushUriTargets",
++ imgTargets, "HttpPushUriTargetsBusy",
++ imgTargetBusy, "Oem", oemProps))
+ {
++ BMCWEB_LOG_DEBUG << "UpdateService doPatch: Invalid request body";
+ return;
+ }
+
++ if (oemProps)
++ {
++ std::optional<nlohmann::json> applyOptions;
++
++ if (!json_util::readJson(*oemProps, asyncResp->res, "ApplyOptions",
++ applyOptions))
++ {
++ return;
++ }
++
++ if (applyOptions)
++ {
++ std::optional<bool> clearConfig;
++ if (!json_util::readJson(*applyOptions, asyncResp->res,
++ "ClearConfig", clearConfig))
++ {
++ return;
++ }
++
++ if (clearConfig)
++ {
++ // Set the requested image apply time value
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "D-Bus responses error: "
++ << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ messages::success(asyncResp->res);
++ },
++ "xyz.openbmc_project.Software.BMC.Updater",
++ "/xyz/openbmc_project/software",
++ "org.freedesktop.DBus.Properties", "Set",
++ "xyz.openbmc_project.Software.ApplyOptions",
++ "ClearConfig", std::variant<bool>{*clearConfig});
++ }
++ }
++ }
++
+ if (pushUriOptions)
+ {
+ std::optional<nlohmann::json> pushUriApplyTime;
+@@ -666,6 +855,98 @@ class UpdateService : public Node
+ }
+ }
+ }
++
++ if (imgTargetBusy)
++ {
++ if ((httpPushUriTargetBusy) && (*imgTargetBusy))
++ {
++ BMCWEB_LOG_DEBUG
++ << "Other client has reserved the HttpPushUriTargets "
++ "property for firmware updates.";
++ messages::resourceInUse(asyncResp->res);
++ return;
++ }
++
++ if (imgTargets)
++ {
++ if (!(*imgTargetBusy))
++ {
++ BMCWEB_LOG_DEBUG
++ << "UpdateService doPatch: httpPushUriTargetBusy "
++ "should be "
++ "true before setting httpPushUriTargets";
++ messages::invalidObject(asyncResp->res,
++ "HttpPushUriTargetsBusy");
++ return;
++ }
++ if ((*imgTargets).size() != 0)
++ {
++ // TODO: Now we support max one target becuase
++ // software-manager code support one activation per object.
++ // It will be enhanced to multiple targets for single image
++ // in future. For now, consider first target alone.
++ if ((*imgTargets).size() != 1)
++ {
++ messages::invalidObject(asyncResp->res,
++ "HttpPushUriTargets");
++ return;
++ }
++ crow::connections::systemBus->async_method_call(
++ [this, asyncResp, uriTargets{*imgTargets},
++ targetBusy{*imgTargetBusy}](
++ const boost::system::error_code ec,
++ const std::vector<std::string> swInvPaths) {
++ if (ec)
++ {
++ return;
++ }
++
++ bool swInvObjFound = false;
++ for (const std::string& path : swInvPaths)
++ {
++ std::size_t idPos = path.rfind("/");
++ if ((idPos == std::string::npos) ||
++ ((idPos + 1) >= path.size()))
++ {
++ messages::internalError(asyncResp->res);
++ BMCWEB_LOG_DEBUG
++ << "Can't parse firmware ID!!";
++ return;
++ }
++ std::string swId = path.substr(idPos + 1);
++
++ if (swId == uriTargets[0])
++ {
++ swInvObjFound = true;
++ break;
++ }
++ }
++ if (!swInvObjFound)
++ {
++ messages::invalidObject(asyncResp->res,
++ "HttpPushUriTargets");
++ return;
++ }
++ this->httpPushUriTargetBusy = targetBusy;
++ this->httpPushUriTargets = uriTargets;
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
++ "/", static_cast<int32_t>(0),
++ std::array<const char*, 1>{versionIntf});
++ }
++ else
++ {
++ httpPushUriTargetBusy = *imgTargetBusy;
++ httpPushUriTargets = *imgTargets;
++ }
++ }
++ else
++ {
++ httpPushUriTargetBusy = *imgTargetBusy;
++ }
++ }
+ }
+
+ void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+@@ -675,8 +956,8 @@ class UpdateService : public Node
+ BMCWEB_LOG_DEBUG << "doPost...";
+
+ // Setup callback for when new software detected
+- monitorForSoftwareAvailable(asyncResp, req,
+- "/redfish/v1/UpdateService");
++ monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService",
++ httpPushUriTargets);
+
+ std::string filepath(
+ "/tmp/images/" +
+@@ -759,7 +1040,7 @@ class SoftwareInventoryCollection : public Node
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/software", static_cast<int32_t>(0),
+- std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
++ std::array<const char*, 1>{versionIntf});
+ }
+ };
+
+@@ -940,7 +1221,7 @@ class SoftwareInventory : public Node
+ },
+ obj.second[0].first, obj.first,
+ "org.freedesktop.DBus.Properties", "GetAll",
+- "xyz.openbmc_project.Software.Version");
++ versionIntf);
+ }
+ if (!found)
+ {
+@@ -961,8 +1242,7 @@ class SoftwareInventory : public Node
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
+- static_cast<int32_t>(0),
+- std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"});
++ static_cast<int32_t>(0), std::array<const char*, 1>{versionIntf});
+ }
+ };
+
+diff --git a/static/redfish/v1/$metadata/index.xml b/static/redfish/v1/$metadata/index.xml
+index 9d9fd1f..6cbc0d1 100644
+--- a/static/redfish/v1/$metadata/index.xml
++++ b/static/redfish/v1/$metadata/index.xml
+@@ -2145,6 +2145,9 @@
+ <edmx:Reference Uri="/redfish/v1/schema/OemComputerSystem_v1.xml">
+ <edmx:Include Namespace="OemComputerSystem"/>
+ </edmx:Reference>
++ <edmx:Reference Uri="/redfish/v1/schema/OemUpdateService_v1.xml">
++ <edmx:Include Namespace="OemUpdateService"/>
++ </edmx:Reference>
+ <edmx:Reference Uri="/redfish/v1/schema/OemVirtualMedia_v1.xml">
+ <edmx:Include Namespace="OemVirtualMedia"/>
+ <edmx:Include Namespace="OemVirtualMedia.v1_0_0"/>
+diff --git a/static/redfish/v1/JsonSchemas/OemUpdateService/index.json b/static/redfish/v1/JsonSchemas/OemUpdateService/index.json
+new file mode 100644
+index 0000000..74e39cd
+--- /dev/null
++++ b/static/redfish/v1/JsonSchemas/OemUpdateService/index.json
+@@ -0,0 +1,69 @@
++{
++ "$id": "http://redfish.dmtf.org/schemas/v1/OemUpdateService.json",
++ "$schema": "http://redfish.dmtf.org/schemas/v1/redfish-schema-v1.json",
++ "copyright": "Copyright 2014-2019 DMTF. For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright",
++ "definitions": {
++ "ApplyOptions": {
++ "additionalProperties": false,
++ "description": "An indication by boolean value whether to update firmware configuration along with firmware image update.",
++ "patternProperties": {
++ "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": {
++ "description": "This property shall specify a valid odata or Redfish property.",
++ "type": [
++ "array",
++ "boolean",
++ "integer",
++ "number",
++ "null",
++ "object",
++ "string"
++ ]
++ }
++ },
++ "properties": {
++ "ClearConfig": {
++ "description": "This indicates whether to update firmware configuration or not.",
++ "longDescription": "The value of this property is used to indicate the firmware configuration update.",
++ "readonly": false,
++ "type": [
++ "boolean",
++ "null"
++ ]
++ }
++ },
++ "type": "object"
++ },
++ "Oem": {
++ "additionalProperties": true,
++ "description": "OemUpdateService Oem properties.",
++ "patternProperties": {
++ "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": {
++ "description": "This property shall specify a valid odata or Redfish property.",
++ "type": [
++ "array",
++ "boolean",
++ "integer",
++ "number",
++ "null",
++ "object",
++ "string"
++ ]
++ }
++ },
++ "properties": {
++ "ApplyOptions": {
++ "anyOf": [
++ {
++ "$ref": "#/definitions/ApplyOptions"
++ },
++ {
++ "type": "null"
++ }
++ ]
++ }
++ },
++ "type": "object"
++ }
++ },
++ "title": "#OemUpdateService"
++}
+diff --git a/static/redfish/v1/schema/OemUpdateService_v1.xml b/static/redfish/v1/schema/OemUpdateService_v1.xml
+new file mode 100644
+index 0000000..cbb7aa4
+--- /dev/null
++++ b/static/redfish/v1/schema/OemUpdateService_v1.xml
+@@ -0,0 +1,40 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
++ <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/errata03/csd01/complete/vocabularies/Org.OData.Core.V1.xml">
++ <edmx:Include Namespace="Org.OData.Core.V1" Alias="OData" />
++ </edmx:Reference>
++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/RedfishExtensions_v1.xml">
++ <edmx:Include Namespace="Validation.v1_0_0" Alias="Validation"/>
++ <edmx:Include Namespace="RedfishExtensions.v1_0_0" Alias="Redfish"/>
++ </edmx:Reference>
++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/UpdateService_v1.xml">
++ <edmx:Include Namespace="UpdateService"/>
++ <edmx:Include Namespace="UpdateService.v1_4_0"/>
++ </edmx:Reference>
++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/Resource_v1.xml">
++ <edmx:Include Namespace="Resource"/>
++ <edmx:Include Namespace="Resource.v1_0_0"/>
++ </edmx:Reference>
++
++ <edmx:DataServices>
++ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="OemUpdateService">
++ <ComplexType Name="Oem" BaseType="Resource.OemObject">
++ <Annotation Term="OData.AdditionalProperties" Bool="true" />
++ <Annotation Term="OData.Description" String="OemUpdateService Oem properties." />
++ <Annotation Term="OData.AutoExpand"/>
++ <Property Name="ApplyOptions" Type="OemUpdateService.ApplyOptions"/>
++ </ComplexType>
++
++ <ComplexType Name="ApplyOptions" BaseType="Resource.OemObject">
++ <Annotation Term="OData.AdditionalProperties" Bool="false" />
++ <Annotation Term="OData.Description" String="An indication by boolean value whether to update firmware configuration along with firmware image update." />
++ <Property Name="ClearConfig" Type="Edm.Boolean">
++ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/ReadWrite"/>
++ <Annotation Term="OData.Description" String="This indicates whether to update firmware configuration or not."/>
++ <Annotation Term="OData.LongDescription" String="The value of this property is used to indicate the firmware configuration update."/>
++ </Property>
++ </ComplexType>
++
++ </Schema>
++ </edmx:DataServices>
++</edmx:Edmx>
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch
new file mode 100644
index 000000000..02f843bb8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch
@@ -0,0 +1,74 @@
+From 034920eca21bc25899565484928ee72025e21ff8 Mon Sep 17 00:00:00 2001
+From: Wiktor Golgowski <wiktor.golgowski@linux.intel.com>
+Date: Thu, 30 Apr 2020 11:09:35 +0200
+Subject: [PATCH] Use chip id-based UUID for Service Root.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If the sysfs-provided chip id is available, it will be used as
+payload to generate Service Root UUID from hardcoded namespace.
+
+Tested:
+Generated UUID is consistent between BMC image reflashes.
+If the sysfs node is not available, code falls back to randomly
+generated UUID.
+
+Signed-off-by: Wiktor Gołgowski <wiktor.golgowski@linux.intel.com>
+---
+ include/persistent_data.hpp | 32 +++++++++++++++++++++++++++++---
+ 1 file changed, 29 insertions(+), 3 deletions(-)
+
+diff --git a/include/persistent_data.hpp b/include/persistent_data.hpp
+index 24f7afd..8826b06 100644
+--- a/include/persistent_data.hpp
++++ b/include/persistent_data.hpp
+@@ -25,6 +25,10 @@ class ConfigFile
+ public:
+ // todo(ed) should read this from a fixed location somewhere, not CWD
+ static constexpr const char* filename = "bmcweb_persistent_data.json";
++ static constexpr const char* chipIdSysfsNode = "/sys/devices/platform"
++ "/ahb/ahb:apb/1e6e2000.syscon/1e6e2000.syscon:misc_control/chip_id";
++ static constexpr const char* UuidNs = "{b7b0553a-54cc-4162-982d-"
++ "944847ed76f5}";
+
+ ConfigFile()
+ {
+@@ -144,9 +148,31 @@ class ConfigFile
+
+ if (systemUuid.empty())
+ {
+- systemUuid =
+- boost::uuids::to_string(boost::uuids::random_generator()());
+- needWrite = true;
++ // Try to retrieve chip id-based uuid.
++ std::ifstream chipIdFile(chipIdSysfsNode);
++ if (chipIdFile.is_open())
++ {
++ std::string chipId;
++ std::getline(chipIdFile, chipId);
++ if (!chipId.empty())
++ {
++ boost::uuids::name_generator_sha1 gen(
++ boost::uuids::string_generator()(UuidNs));
++ systemUuid = boost::uuids::to_string(gen(chipId.c_str()));
++ needWrite = true;
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "Cannot get chip id-based System UUID.";
++ }
++ }
++ // If the above fails, generate random uuid.
++ if (systemUuid.empty())
++ {
++ systemUuid =
++ boost::uuids::to_string(boost::uuids::random_generator()());
++ needWrite = true;
++ }
+ }
+ if (fileRevision < jsonRevision)
+ {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch
new file mode 100644
index 000000000..d962d3872
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch
@@ -0,0 +1,67 @@
+From b5e4edfc26eec245427d3435de9acaa9363ae836 Mon Sep 17 00:00:00 2001
+From: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+Date: Mon, 28 Dec 2020 18:55:57 +0000
+Subject: [PATCH] managers: add attributes for Manager.CommandShell
+
+Issue: ConnectTypesSupported, ServiceEnabled and
+ MaxConcurrentSessions Attributes are missing for
+ Manager.CommandShell, though Requirement mandates it.
+
+Fix: Added missing attributes to Manager.CommandShell
+
+Tested:
+1. Verified redfish validator passed
+2. Get bmc details from Redfish
+Redfish URI: https://<BMC IP>/redfish/v1/Managers/bmc
+Response:
+{
+ "@odata.id": "/redfish/v1/Managers/bmc",
+ "@odata.type": "#Manager.v1_9_0.Manager",
+....
+....
+ "CommandShell": {
+ "ConnectTypesSupported": [
+ "SSH",
+ "IPMI"
+ ],
+ "MaxConcurrentSessions": 4,
+ "ServiceEnabled": true
+ },
+....
+....
+
+Signed-off-by: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+---
+ redfish-core/lib/managers.hpp | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
+index 67f8d99..dcbc347 100644
+--- a/redfish-core/lib/managers.hpp
++++ b/redfish-core/lib/managers.hpp
+@@ -1830,6 +1830,13 @@ class Manager : public Node
+ asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15;
+ asyncResp->res.jsonValue["SerialConsole"]["ConnectTypesSupported"] = {
+ "IPMI", "SSH"};
++
++ // Fill in CommandShell info
++ asyncResp->res.jsonValue["CommandShell"]["ServiceEnabled"] = true;
++ asyncResp->res.jsonValue["CommandShell"]["MaxConcurrentSessions"] = 4;
++ asyncResp->res.jsonValue["CommandShell"]["ConnectTypesSupported"] = {
++ "SSH", "IPMI"};
++
+ #ifdef BMCWEB_ENABLE_KVM
+ // Fill in GraphicalConsole info
+ asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true;
+@@ -2272,7 +2279,7 @@ class Manager : public Node
+ }
+
+ std::string uuid;
+-};
++}; // namespace redfish
+
+ class ManagerCollection : public Node
+ {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch
new file mode 100644
index 000000000..e52dff3f4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-bmcweb-Add-PhysicalContext-to-Thermal-resources.patch
@@ -0,0 +1,135 @@
+From b9747ecfce682f15dce0bb6e41e0c894f29419f3 Mon Sep 17 00:00:00 2001
+From: Snehalatha Venkatesh <snehalathax.v@intel.com>
+Date: Thu, 8 Apr 2021 14:42:07 +0000
+Subject: [PATCH] bmcweb: Add PhysicalContext to Thermal resources
+
+Adding PhysicalContext to make redfish data compliance with OCP
+Server Mgmt Interface v0.2.1.pdf and specific to Thermal resources.
+https://github.com/opencomputeproject/OCP-Profiles/blob/master/
+OCPServerHardwareManagement.v0_2_4.json
+
+Tested:
+1. Redfish validator - passed for this new change
+2. GET - https://<bmc.ip>/redfish/v1/Chassis/<Board>/Thermal
+Response:
+{
+ "@odata.id": "/redfish/v1/Chassis/<Board>/Thermal#/Temperatures/0",
+ "@odata.type": "#Thermal.v1_3_0.Temperature",
+ "LowerThresholdCritical": 0.0,
+ "LowerThresholdNonCritical": 5.0,
+ "MaxReadingRangeTemp": 127.0,
+ "MemberId": "BMC_Temp",
+ "MinReadingRangeTemp": -128.0,
+ "Name": "BMC Temp",
+ "PhysicalContext": "SystemBoard",
+ "ReadingCelsius": 25.75,
+ "Status": {
+ "Health": "OK",
+ "State": "Enabled"
+ },
+ "UpperThresholdCritical": 115.0,
+ "UpperThresholdNonCritical": 110.0
+},
+{
+ "@odata.id": "/redfish/v1/Chassis/<Board>/Thermal#/Temperatures/1",
+ "@odata.type": "#Thermal.v1_3_0.Temperature",
+ "LowerThresholdCritical": 0.0,
+ "LowerThresholdNonCritical": 5.0,
+ "MaxReadingRangeTemp": 255.0,
+ "MemberId": "CPU1_P12V_PVCCIN_VR_Temp",
+ "MinReadingRangeTemp": 0.0,
+ "Name": "CPU1 P12V PVCCIN VR Temp",
+ "PhysicalContext": "CPU",
+ "ReadingCelsius": 41.0,
+ "Status": {
+ "Health": "OK",
+ "State": "Enabled"
+ },
+ "UpperThresholdCritical": 115.0,
+ "UpperThresholdNonCritical": 110.0
+},
+{
+ "@odata.id": "/redfish/v1/Chassis/<Board>/Thermal#/Temperatures/28",
+ "@odata.type": "#Thermal.v1_3_0.Temperature",
+ "LowerThresholdCritical": 0.0,
+ "LowerThresholdNonCritical": 5.0,
+ "MaxReadingRangeTemp": 127.0,
+ "MemberId": "Inlet_BRD_Temp",
+ "MinReadingRangeTemp": -128.0,
+ "Name": "Inlet BRD Temp",
+ "PhysicalContext": "Intake",
+ "ReadingCelsius": 23.187,
+ "Status": {
+ "Health": "OK",
+ "State": "Enabled"
+ },
+ "UpperThresholdCritical": 115.0,
+ "UpperThresholdNonCritical": 110.0
+}
+3. GET - https://<bmc.ip>/redfish/v1/Chassis/<Board>/Power
+Response:
+{
+ "@odata.id": "/redfish/v1/Chassis/<Board>/Power#/Voltages/3",
+ "@odata.type": "#Power.v1_0_0.Voltage",
+ "LowerThresholdCritical": 1.648,
+ "LowerThresholdNonCritical": 1.699,
+ "MaxReadingRange": 2.3984009912875566,
+ "MemberId": "P1V8_PCH",
+ "MinReadingRange": 0.0,
+ "Name": "P1V8 PCH",
+ "ReadingVolts": 1.8055,
+ "Status": {
+ "Health": "OK",
+ "State": "Enabled"
+ },
+ "UpperThresholdCritical": 1.961,
+ "UpperThresholdNonCritical": 1.904
+}
+4. GET - https://<bmc.ip>/redfish/v1/Chassis/<Board>/Sensors/PSU1_Input_Current
+Response:
+{
+ "@odata.id": "/redfish/v1/Chassis/<Board>/Sensors/PSU1_Input_Current",
+ "@odata.type": "#Sensor.v1_0_0.Sensor",
+ "Id": "PSU1_Input_Current",
+ "Name": "PSU1 Input Current",
+ "Reading": 0.947,
+ "ReadingRangeMax": 12.0,
+ "ReadingRangeMin": 0.0,
+ "ReadingType": "Current",
+ "ReadingUnits": "A",
+ "Status": {
+ "Health": "OK",
+ "State": "Enabled"
+ }
+}
+Signed-off-by: Snehalatha Venkatesh <snehalathax.v@intel.com>
+---
+ redfish-core/lib/sensors.hpp | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
+index 9f06d2f..40fcdf8 100644
+--- a/redfish-core/lib/sensors.hpp
++++ b/redfish-core/lib/sensors.hpp
+@@ -964,6 +964,18 @@ inline void objectInterfacesToJson(
+ {
+ unit = "/ReadingCelsius"_json_pointer;
+ sensorJson["@odata.type"] = "#Thermal.v1_3_0.Temperature";
++ if (sensorName.find("CPU") != std::string::npos)
++ {
++ sensorJson["PhysicalContext"] = "CPU";
++ }
++ else if (sensorName.find("Inlet") != std::string::npos)
++ {
++ sensorJson["PhysicalContext"] = "Intake";
++ }
++ else
++ {
++ sensorJson["PhysicalContext"] = "SystemBoard";
++ }
+ // TODO(ed) Documentation says that path should be type fan_tach,
+ // implementation seems to implement fan
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-Log-RedFish-event-for-Invalid-login-attempt.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-Log-RedFish-event-for-Invalid-login-attempt.patch
new file mode 100644
index 000000000..3ef4ee2de
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-Log-RedFish-event-for-Invalid-login-attempt.patch
@@ -0,0 +1,67 @@
+From 1f572a1991fc8d9b08689aa6e3470080467977a7 Mon Sep 17 00:00:00 2001
+From: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+Date: Thu, 15 Apr 2021 10:59:42 +0000
+Subject: [PATCH] Log RedFish event for Invalid login attempt
+
+This commit adds support for logging RedFish event log while user tries
+to attempt login with invalid credentials.
+When user trying to login with invalid credentials on HTTPS interface
+like WebUI and RedFish, event should be logged in RedFish event log.
+This event log is useful for further analysis to debug the root-cause
+for failure.
+
+Tested:
+1. Verified RedFish validator passed
+2. Login with wrong credentials on HTTPS interface.
+3. Verified for RedFish/WebUI events. RedFish event logged successfully.
+GET: https://BMC-IP/redfish/v1/Systems/system/LogServices/
+ EventLog/Entries
+Response:
+"Members": [
+{
+ "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/
+ Entries/1618466128",
+ "@odata.type": "#LogEntry.v1_4_0.LogEntry",
+ "Created": "2021-04-15T05:55:28+00:00",
+ "EntryType": "Event",
+ "Id": "1618466128",
+ "Message": "Invalid username or password attempted on HTTPS.",
+ "MessageArgs": [
+ "HTTPS"
+ ],
+ "MessageId": "OpenBMC.0.1.InvalidLoginAttempted",
+ "Name": "System Event Log Entry",
+ "Severity": "Warning"
+}
+
+Signed-off-by: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+---
+ include/pam_authenticate.hpp | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp
+index 12f19c0..01bf301 100644
+--- a/include/pam_authenticate.hpp
++++ b/include/pam_authenticate.hpp
+@@ -1,6 +1,7 @@
+ #pragma once
+
+ #include <security/pam_appl.h>
++#include <systemd/sd-journal.h>
+
+ #include <boost/utility/string_view.hpp>
+
+@@ -75,6 +76,10 @@ inline int pamAuthenticateUser(const std::string_view username,
+ PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
+ if (retval != PAM_SUCCESS)
+ {
++ sd_journal_send("MESSAGE= %s", "Invalid login attempted on HTTPS",
++ "PRIORITY=%i", LOG_WARNING, "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.InvalidLoginAttempted",
++ "REDFISH_MESSAGE_ARGS=%s", "HTTPS", NULL);
+ pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval
+ return retval;
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-Add-UART-routing-logic-into-host-console-connection-.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-Add-UART-routing-logic-into-host-console-connection-.patch
new file mode 100644
index 000000000..8b0d90fe0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-Add-UART-routing-logic-into-host-console-connection-.patch
@@ -0,0 +1,59 @@
+From 6c10adb53d3247f65e5d9399290e6b8e7962cdef Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 28 Apr 2021 17:19:50 -0700
+Subject: [PATCH] Add UART routing logic into host console connection flow
+
+Switching UART routing when starting obmc-service introduces garbled
+character printing out on physical host serial output and it's
+inevitable so this commit moves the routing logic into host console
+connection flow in bmcweb to avoid the issue until SOL is actually
+activated.
+
+Tested: The garbled character printing out was not observed during
+BMC booting. SOL worked well.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ include/obmc_console.hpp | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+diff --git a/include/obmc_console.hpp b/include/obmc_console.hpp
+index cdb19901e82d..9c4ae8821074 100644
+--- a/include/obmc_console.hpp
++++ b/include/obmc_console.hpp
+@@ -22,6 +22,9 @@ static boost::container::flat_set<crow::websocket::Connection*> sessions;
+
+ static bool doingWrite = false;
+
++constexpr char const* uartMuxCtrlPath = "/sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/raw";
++constexpr char const* uartMuxCtrlVal = "0x03450003";
++
+ inline void doWrite()
+ {
+ if (doingWrite)
+@@ -110,6 +113,22 @@ inline void connectHandler(const boost::system::error_code& ec)
+ return;
+ }
+
++ FILE* file = fopen(uartMuxCtrlPath, "w");
++ if (file != nullptr)
++ {
++ int rc = fputs(uartMuxCtrlVal, file);
++ fclose(file);
++ if (rc < 0)
++ {
++ BMCWEB_LOG_ERROR << "Couldn't change UART routing: " << rc;
++ for (crow::websocket::Connection* session : sessions)
++ {
++ session->close("Error in connecting to host port");
++ }
++ return;
++ }
++ }
++
+ doWrite();
+ doRead();
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-recommended-fixes-by-crypto-review-team.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-recommended-fixes-by-crypto-review-team.patch
new file mode 100644
index 000000000..5ffc259c0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-recommended-fixes-by-crypto-review-team.patch
@@ -0,0 +1,75 @@
+From aaaa117817687a05284f8bfff07e2404e0d616b7 Mon Sep 17 00:00:00 2001
+From: Radivoje Jovanovic <radivoje.jovanovic@intel.com>
+Date: Thu, 10 Dec 2020 13:42:20 -0800
+Subject: [PATCH] recommended fixes by crypto review team
+
+some curves/cyphers are forbiden to be used by
+Intel crypto team.
+Only enable approved ones.
+the patch was created by aleksandr.v.tereschenko@intel.com
+
+Signed-off-by: Radivoje Jovanovic <radivoje.jovanovic@intel.com>
+---
+ include/ssl_key_handler.hpp | 39 ++++++++++++++++++++-----------------
+ 1 file changed, 21 insertions(+), 18 deletions(-)
+
+diff --git a/include/ssl_key_handler.hpp b/include/ssl_key_handler.hpp
+index 39e83d7..8de7349 100644
+--- a/include/ssl_key_handler.hpp
++++ b/include/ssl_key_handler.hpp
+@@ -381,31 +381,34 @@ inline std::shared_ptr<boost::asio::ssl::context>
+ mSslContext->use_private_key_file(sslPemFile,
+ boost::asio::ssl::context::pem);
+
+- // Set up EC curves to auto (boost asio doesn't have a method for this)
+- // There is a pull request to add this. Once this is included in an asio
+- // drop, use the right way
+- // http://stackoverflow.com/questions/18929049/boost-asio-with-ecdsa-certificate-issue
+- if (SSL_CTX_set_ecdh_auto(mSslContext->native_handle(), 1) != 1)
++ std::string handshakeCurves = "P-384:P-521:X448";
++ if (SSL_CTX_set1_groups_list(mSslContext->native_handle(), handshakeCurves.c_str()) != 1)
+ {
+- BMCWEB_LOG_ERROR << "Error setting tmp ecdh list\n";
++ BMCWEB_LOG_ERROR << "Error setting ECDHE group list\n";
+ }
+
+- std::string mozillaModern = "ECDHE-ECDSA-AES256-GCM-SHA384:"
+- "ECDHE-RSA-AES256-GCM-SHA384:"
+- "ECDHE-ECDSA-CHACHA20-POLY1305:"
+- "ECDHE-RSA-CHACHA20-POLY1305:"
+- "ECDHE-ECDSA-AES128-GCM-SHA256:"
+- "ECDHE-RSA-AES128-GCM-SHA256:"
+- "ECDHE-ECDSA-AES256-SHA384:"
+- "ECDHE-RSA-AES256-SHA384:"
+- "ECDHE-ECDSA-AES128-SHA256:"
+- "ECDHE-RSA-AES128-SHA256";
++ std::string tls12Ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384:"
++ "ECDHE-RSA-AES256-GCM-SHA384";
++ std::string tls13Ciphers = "TLS_AES_256_GCM_SHA384";
+
+ if (SSL_CTX_set_cipher_list(mSslContext->native_handle(),
+- mozillaModern.c_str()) != 1)
++ tls12Ciphers.c_str()) != 1)
+ {
+- BMCWEB_LOG_ERROR << "Error setting cipher list\n";
++ BMCWEB_LOG_ERROR << "Error setting TLS 1.2 cipher list\n";
+ }
++
++ if (SSL_CTX_set_ciphersuites(mSslContext->native_handle(),
++ tls13Ciphers.c_str()) != 1)
++ {
++ BMCWEB_LOG_ERROR << "Error setting TLS 1.3 cipher list\n";
++ }
++
++ if ((SSL_CTX_set_options(mSslContext->native_handle(),
++ SSL_OP_CIPHER_SERVER_PREFERENCE) & SSL_OP_CIPHER_SERVER_PREFERENCE) == 0)
++ {
++ BMCWEB_LOG_ERROR << "Error setting TLS server preference option\n";
++ }
++
+ return mSslContext;
+ }
+ } // namespace ensuressl
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-state-sensor-messages-to-the-registry.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-state-sensor-messages-to-the-registry.patch
new file mode 100644
index 000000000..b171a8b2c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-state-sensor-messages-to-the-registry.patch
@@ -0,0 +1,98 @@
+From df571ddf0596f73c0318da3a90b9813e6df19dd9 Mon Sep 17 00:00:00 2001
+From: "Arun P. Mohanan" <arun.p.m@linux.intel.com>
+Date: Wed, 27 Jan 2021 18:22:58 +0530
+Subject: [PATCH] Add state sensor messages to the registry
+
+Add messages to registry to indicate state sensor state change.
+
+Tested:
+Build and redfish validator passes.
+Logged these events and confirmed that they appear as expected on
+Redfish.
+GET: https://<BMC IP>/redfish/v1/Systems/system/LogServices/EventLog/Entries/1612528180
+{
+ "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/1612528180",
+ "@odata.type": "#LogEntry.v1_4_0.LogEntry",
+ "Created": "2021-02-05T12:29:40+00:00",
+ "EntryType": "Event",
+ "Id": "1612528180",
+ "Message": "Operational Fault Status of Card_health_1 state sensor changed from Error to Normal.",
+ "MessageArgs": [
+ "Operational Fault Status",
+ "Card_health_1",
+ "Error",
+ "Normal"
+ ],
+ "MessageId": "OpenBMC.0.1.StateSensorNormal",
+ "Name": "System Event Log Entry",
+ "Severity": "OK"
+}
+
+Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com>
+---
+ .../registries/openbmc_message_registry.hpp | 36 +++++++++++++++++--
+ 1 file changed, 34 insertions(+), 2 deletions(-)
+
+diff --git a/redfish-core/include/registries/openbmc_message_registry.hpp b/redfish-core/include/registries/openbmc_message_registry.hpp
+index 5eb9380..dbea97c 100644
+--- a/redfish-core/include/registries/openbmc_message_registry.hpp
++++ b/redfish-core/include/registries/openbmc_message_registry.hpp
+@@ -29,7 +29,7 @@ const Header header = {
+ "0.1.0",
+ "OpenBMC",
+ };
+-constexpr std::array<MessageEntry, 187> registry = {
++constexpr std::array<MessageEntry, 190> registry = {
+ MessageEntry{
+ "ADDDCCorrectable",
+ {
+@@ -2318,6 +2318,39 @@ constexpr std::array<MessageEntry, 187> registry = {
+ {},
+ "None.",
+ }},
++ MessageEntry{
++ "StateSensorNormal",
++ {
++ "Indicates that a state sensor has changed state to normal.",
++ "%1 of %2 state sensor changed from %3 to %4.",
++ "OK",
++ "OK",
++ 4,
++ {"string", "string", "string", "string"},
++ "None.",
++ }},
++ MessageEntry{
++ "StateSensorWarning",
++ {
++ "Indicates that a state sensor has changed state to warning.",
++ "%1 of %2 state sensor changed from %3 to %4.",
++ "Warning",
++ "Warning",
++ 4,
++ {"string", "string", "string", "string"},
++ "Check sensor subsystem for errors.",
++ }},
++ MessageEntry{
++ "StateSensorCritical",
++ {
++ "Indicates that a state sensor has changed state to critical.",
++ "%1 of %2 state sensor changed from %3 to %4.",
++ "Critical",
++ "Critical",
++ 4,
++ {"string", "string", "string", "string"},
++ "Check sensor subsystem for errors.",
++ }},
+ MessageEntry{"SystemInterfaceDisabledProvisioned",
+ {
+ "Indicates that the system interface is in the disabled "
+@@ -2410,6 +2443,5 @@ constexpr std::array<MessageEntry, 187> registry = {
+ {"string"},
+ "None.",
+ }},
+-
+ };
+ } // namespace redfish::message_registries::openbmc
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-Fix-bmcweb-crashes-if-socket-directory-not-present.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-Fix-bmcweb-crashes-if-socket-directory-not-present.patch
new file mode 100644
index 000000000..bc023839f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-Fix-bmcweb-crashes-if-socket-directory-not-present.patch
@@ -0,0 +1,44 @@
+From 48fe2a68d634970795f9ff13903afbedca801088 Mon Sep 17 00:00:00 2001
+From: Nidhin MS <nidhin.ms@intel.com>
+Date: Wed, 14 Apr 2021 11:28:44 +0530
+Subject: [PATCH] Fix: bmcweb crashes if socket directory not present
+
+When trying to mount virtual media image bmcweb tries to create unix
+socket and if the parent directory does not exist
+stream_protocol::acceptor throws error and bmcweb crashes. Fix the same
+
+Tested:
+Removed directory and mounted the vm image. bmcweb crash was not
+observed
+
+Change-Id: I3aea1d8e197c06238f425a97435c01d3c80552a9
+Signed-off-by: Nidhin MS <nidhin.ms@intel.com>
+---
+ include/nbd_proxy.hpp | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/include/nbd_proxy.hpp b/include/nbd_proxy.hpp
+index 7b90e90..3b28823 100644
+--- a/include/nbd_proxy.hpp
++++ b/include/nbd_proxy.hpp
+@@ -397,6 +397,17 @@ inline void requestRoutes(App& app)
+ // If the socket file exists (i.e. after bmcweb crash),
+ // we cannot reuse it.
+ std::remove((*socketValue).c_str());
++ std::filesystem::path socketPath(*socketValue);
++ std::error_code fsErr;
++ if (!std::filesystem::exists(socketPath.parent_path(),
++ fsErr))
++ {
++ BMCWEB_LOG_ERROR
++ << "VirtualMedia socket directory not present. "
++ << socketPath.parent_path();
++ conn.close("Unable to create unix socket");
++ return;
++ }
+
+ sessions[&conn] = std::make_shared<NbdProxyServer>(
+ conn, *socketValue, *endpointValue,
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-msg-registry-for-subscription-related-actions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-msg-registry-for-subscription-related-actions.patch
new file mode 100644
index 000000000..d0cfd1c44
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-msg-registry-for-subscription-related-actions.patch
@@ -0,0 +1,81 @@
+From 7282ab7756cdb8c844bef9affd8a8e894828678c Mon Sep 17 00:00:00 2001
+From: Ayushi Smriti <smriti.ayushi@intel.com>
+Date: Mon, 10 May 2021 12:32:30 +0530
+Subject: [PATCH] Add msg registry for subscription related actions
+
+For subscription event message log purpose, added message registry
+entry for event service subscription related actions- add, update
+and delete.
+
+Tested:
+ - Message registry entry appears in the log for the corresponding
+ subscription action.
+
+Signed-off-by: AppaRao Puli <apparao.puli@intel.com>
+Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com>
+---
+ .../registries/openbmc_message_registry.hpp | 41 ++++++++++++++++++-
+ 1 file changed, 40 insertions(+), 1 deletion(-)
+
+diff --git a/redfish-core/include/registries/openbmc_message_registry.hpp b/redfish-core/include/registries/openbmc_message_registry.hpp
+index e12a138..2f981db 100644
+--- a/redfish-core/include/registries/openbmc_message_registry.hpp
++++ b/redfish-core/include/registries/openbmc_message_registry.hpp
+@@ -29,7 +29,7 @@ const Header header = {
+ "0.2.0",
+ "OpenBMC",
+ };
+-constexpr std::array<MessageEntry, 190> registry = {
++constexpr std::array<MessageEntry, 193> registry = {
+ MessageEntry{
+ "ADDDCCorrectable",
+ {
+@@ -417,6 +417,45 @@ constexpr std::array<MessageEntry, 190> registry = {
+ {},
+ "None.",
+ }},
++ MessageEntry{"EventSubscriptionAdded",
++ {
++ "Indicates that an Event subscription with specific "
++ "id was added.",
++ "Event subscription with id %1 was added.",
++ "OK",
++ "OK",
++ 1,
++ {
++ "string",
++ },
++ "None.",
++ }},
++ MessageEntry{"EventSubscriptionRemoved",
++ {
++ "Indicates that an Event subscription with specific "
++ "id was removed.",
++ "Event subscription with id %1 was removed.",
++ "OK",
++ "OK",
++ 1,
++ {
++ "string",
++ },
++ "None.",
++ }},
++ MessageEntry{"EventSubscriptionUpdated",
++ {
++ "Indicates that an Event subscription with specific "
++ " id was updated.",
++ "Event subscription with id %1 was updated.",
++ "OK",
++ "OK",
++ 1,
++ {
++ "string",
++ },
++ "None.",
++ }},
+ MessageEntry{"FanInserted",
+ {
+ "Indicates that a system fan has been inserted.",
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-bmcweb-Add-BMC-Time-update-log-to-the-registry.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-bmcweb-Add-BMC-Time-update-log-to-the-registry.patch
new file mode 100644
index 000000000..829384305
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-bmcweb-Add-BMC-Time-update-log-to-the-registry.patch
@@ -0,0 +1,77 @@
+From 3ec1f79d1cb29724e345586f0baefca81d98d3ae Mon Sep 17 00:00:00 2001
+From: mansijos <mansi.joshi@intel.com>
+Date: Wed, 26 May 2021 17:40:04 +0530
+Subject: [PATCH] [bmcweb] Add BMC Time update log to the registry
+
+Add message in registry to log an event that indicates BMC time
+is set via NTP, Host or Manually.
+During early stage of system boot if any critical events occur,
+they are getting logged with 1970 timestamp till the time BMC
+time update happens. This is expected behavior, but to call it out
+explicitly it is good to log when BMC time is updated.
+
+Tested:
+Built and validator passes.
+Confirmed that the event is getting logged correctly in Redfish.
+
+Signed-off-by: mansijos <mansi.joshi@intel.com>
+---
+ .../registries/openbmc_message_registry.hpp | 35 ++++++++++++++++++-
+ 1 file changed, 34 insertions(+), 1 deletion(-)
+
+diff --git a/redfish-core/include/registries/openbmc_message_registry.hpp b/redfish-core/include/registries/openbmc_message_registry.hpp
+index 2f981db..a00d235 100644
+--- a/redfish-core/include/registries/openbmc_message_registry.hpp
++++ b/redfish-core/include/registries/openbmc_message_registry.hpp
+@@ -29,7 +29,7 @@ const Header header = {
+ "0.2.0",
+ "OpenBMC",
+ };
+-constexpr std::array<MessageEntry, 193> registry = {
++constexpr std::array<MessageEntry, 196> registry = {
+ MessageEntry{
+ "ADDDCCorrectable",
+ {
+@@ -286,6 +286,39 @@ constexpr std::array<MessageEntry, 193> registry = {
+ {},
+ "None.",
+ }},
++ MessageEntry{"BMCTimeUpdatedViaHost",
++ {
++ "Indicates that BMC time has been set via Host.",
++ "BMC time has been set via Host. "
++ "Date Time is set to %1 from %2.",
++ "OK",
++ "OK",
++ 2,
++ {"string", "string"},
++ "None.",
++ }},
++ MessageEntry{"BMCTimeUpdatedManually",
++ {
++ "Indicates that BMC time has been set Manually.",
++ "BMC time has been set Manually. "
++ "Date Time is set to %1 from %2.",
++ "OK",
++ "OK",
++ 2,
++ {"string", "string"},
++ "None.",
++ }},
++ MessageEntry{"BMCTimeUpdatedViaNTP",
++ {
++ "Indicates that BMC time has been set via NTP.",
++ "BMC time has been set via NTP. "
++ "Date Time is set to %1 from %2.",
++ "OK",
++ "OK",
++ 2,
++ {"string", "string"},
++ "None.",
++ }},
+ MessageEntry{"ChassisIntrusionDetected",
+ {
+ "Indicates that a physical security event "
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-Add-generic-message-PropertySizeExceeded.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-Add-generic-message-PropertySizeExceeded.patch
new file mode 100644
index 000000000..756ea24d7
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-Add-generic-message-PropertySizeExceeded.patch
@@ -0,0 +1,118 @@
+From da893566ec02aefe235685f1b6742269aab37909 Mon Sep 17 00:00:00 2001
+From: Nitin Wankhade <nitinx.arunrao.wankhade@intel.com>
+Date: Thu, 24 Jun 2021 15:29:24 +0000
+Subject: [PATCH] Add generic message - PropertySizeExceeded
+
+Adding a generic error message "PropertySizeExceeded"
+to address properties which exceed there defined size limit.
+
+Tested:
+No functional change. Build passed.
+Verified by explicitly sending this message as a response.
+
+Change-Id: I0e9f85f82a69c598e169fc8e9a68c3f66c0084d8
+Signed-off-by: Nitin Wankhade <nitinx.arunrao.wankhade@intel.com>
+---
+ redfish-core/include/error_messages.hpp | 12 +++++++++
+ .../registries/base_message_registry.hpp | 17 +++++++++++-
+ redfish-core/src/error_messages.cpp | 27 +++++++++++++++++++
+ 3 files changed, 55 insertions(+), 1 deletion(-)
+
+diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp
+index 922dae9..586246c 100644
+--- a/redfish-core/include/error_messages.hpp
++++ b/redfish-core/include/error_messages.hpp
+@@ -222,6 +222,18 @@ nlohmann::json propertyValueFormatError(const std::string& arg1,
+ void propertyValueFormatError(crow::Response& res, const std::string& arg1,
+ const std::string& arg2);
+
++/**
++ * @brief Formats PropertySizeExceeded message into JSON
++ * Message body: "The property <arg1> is too long. The value exceeds its size
++ * limit."
++ *
++ * @param[in] arg1 Parameter of message that will replace %1 in its body.
++ *
++ * @returns Message PropertySizeExceeded formatted to JSON */
++nlohmann::json propertySizeExceeded(const std::string& arg1);
++
++void propertySizeExceeded(crow::Response& res, const std::string& arg1);
++
+ /**
+ * @brief Formats PropertyValueNotInList message into JSON
+ * Message body: "The value <arg1> for the property <arg2> is not in the list of
+diff --git a/redfish-core/include/registries/base_message_registry.hpp b/redfish-core/include/registries/base_message_registry.hpp
+index 7c385a0..79d324e 100644
+--- a/redfish-core/include/registries/base_message_registry.hpp
++++ b/redfish-core/include/registries/base_message_registry.hpp
+@@ -36,7 +36,7 @@ const Header header = {
+ constexpr const char* url =
+ "https://redfish.dmtf.org/registries/Base.1.8.1.json";
+
+-constexpr std::array<MessageEntry, 74> registry = {
++constexpr std::array<MessageEntry, 75> registry = {
+ MessageEntry{
+ "AccessDenied",
+ {
+@@ -592,6 +592,21 @@ constexpr std::array<MessageEntry, 74> registry = {
+ "Remove the property from the request body and resubmit "
+ "the request if the operation failed.",
+ }},
++ MessageEntry{"PropertySizeExceeded",
++ {
++ "Indicates that a given property exceeds the size "
++ "limit imposed.",
++ "The property %1 is too long. The value exceeds "
++ "its size limit.",
++ "Warning",
++ "Warning",
++ 1,
++ {
++ "string",
++ },
++ "Correct the value for the property in the request body "
++ "and resubmit the request if the operation failed.",
++ }},
+ MessageEntry{"PropertyUnknown",
+ {
+ "Indicates that an unknown property was included in the "
+diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp
+index 409adb1..11e59be 100644
+--- a/redfish-core/src/error_messages.cpp
++++ b/redfish-core/src/error_messages.cpp
+@@ -514,6 +514,33 @@ void propertyValueFormatError(crow::Response& res, const std::string& arg1,
+ addMessageToJson(res.jsonValue, propertyValueFormatError(arg1, arg2), arg2);
+ }
+
++/**
++ * @internal
++ * @brief Formats PropertySizeExceeded message into JSON for the specified
++ * property
++ *
++ * See header file for more information
++ * @endinternal
++ */
++nlohmann::json propertySizeExceeded(const std::string& arg1)
++{
++ return nlohmann::json{
++ {"@odata.type", "#Message.v1_1_1.Message"},
++ {"MessageId", "Base.1.8.1.PropertySizeExceeded"},
++ {"Message", "The property " + arg1 +
++ " is too long. The value exceeds its size limit."},
++ {"MessageArgs", {arg1}},
++ {"MessageSeverity", "Warning"},
++ {"Resolution", "Correct the value for the property in the request body "
++ "and resubmit the request if the operation failed."}};
++}
++
++void propertySizeExceeded(crow::Response& res, const std::string& arg1)
++{
++ res.result(boost::beast::http::status::bad_request);
++ addMessageToJson(res.jsonValue, propertySizeExceeded(arg1), arg1);
++}
++
+ /**
+ * @internal
+ * @brief Formats PropertyValueNotInList message into JSON for the specified
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0001-Define-Redfish-interface-Registries-Bios.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0001-Define-Redfish-interface-Registries-Bios.patch
new file mode 100644
index 000000000..9cf4653d6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0001-Define-Redfish-interface-Registries-Bios.patch
@@ -0,0 +1,848 @@
+From 72c273ae74bb6add062b89f59ebeee4d4eb7e523 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Fri, 4 Sep 2020 19:24:25 +0800
+Subject: [PATCH] Define Redfish interface "/Registries/Bios" and enable
+ Attributes property
+
+1. Define Redfish interface "/Registries/Bios" for BIOS Attribute Registry
+ RBC Daemon provide method to get BIOS attribute registry.
+2. Eanble Attributes property for BIOS resource
+3. Define Redfish interface "/Systems/system/Bios/Settings" for BIOS
+settings
+4. RBC daemon is at
+https://gerrit.openbmc-project.xyz/#/c/openbmc/bios-settings-mgr/+/35563/
+5. IPMI command implementation is at
+https://gerrit.openbmc-project.xyz/#/c/openbmc/intel-ipmi-oem/+/30827/
+6. Property design is at
+https://github.com/openbmc/phosphor-dbus-interfaces/tree/master/xyz/openbmc_project/BIOSConfig
+7. Design doc is at
+https://github.com/openbmc/docs/blob/master/designs/remote-bios-configuration.md
+8. There will be 95 test cases for this feature in the validation team.
+
+Tested:
+
+1. Use postman (Redfish tool) could get all the attributes in bios
+resouce, get bios settings, get bios attribute
+registry.
+https://IP_ADDR/redfish/v1/Systems/system/Bios
+{
+ "@Redfish.Settings": {
+ "@odata.type": "#Settings.v1_3_0.Settings",
+ "SettingsObject": {
+ "@odata.id": "/redfish/v1/Systems/system/Bios/Settings"
+ }
+ },
+ "@odata.id": "/redfish/v1/Systems/system/Bios",
+ "@odata.type": "#Bios.v1_1_0.Bios",
+ "Actions": {
+ "#Bios.ChangePassword": {
+ "target": "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword"
+ },
+ "#Bios.ResetBios": {
+ "target": "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios"
+ }
+ },
+ "AttributeRegistry": "BiosAttributeRegistry",
+ "Attributes": {
+ "attr0": "current value"
+ },
+ "Description": "BIOS Configuration Service",
+ "Id": "BIOS",
+ "Links": {
+ "ActiveSoftwareImage": {
+ "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bios_active"
+ },
+ "SoftwareImages": [
+ {
+ "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bios_active"
+ }
+ ],
+ "SoftwareImages@odata.count": 1
+ },
+ "Name": "BIOS Configuration"
+}
+
+Redfish interface: https://BMCIP/redfish/v1/Registries/BiosAttributeRegistry
+{
+ "@odata.id": "/redfish/v1/Registries/BiosAttributeRegistry",
+ "@odata.type": "#MessageRegistryFile.v1_1_0.MessageRegistryFile",
+ "Description": "BiosAttributeRegistry Message Registry File Location",
+ "Id": "BiosAttributeRegistry",
+ "Languages": [
+ "en"
+ ],
+ "Languages@odata.count": 1,
+ "Location": [
+ {
+ "Language": "en",
+ "Uri": "/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry"
+ }
+ ],
+ "Location@odata.count": 1,
+ "Name": "BiosAttributeRegistry Message Registry File",
+ "Registry": "BiosAttributeRegistry.1.0.0"
+}
+
+Redfish interface: https://BMCIP/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry
+{
+ "@odata.id": "/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry",
+ "@odata.type": "#AttributeRegistry.v1_3_2.AttributeRegistry",
+ "Id": "BiosAttributeRegistry",
+ "Language": "en",
+ "Name": "Bios Attribute Registry",
+ "OwningEntity": "OpenBMC",
+ "RegistryEntries": {
+ "Attributes": [
+ {
+ "AttributeName": "attr0",
+ "CurrentValue": "current value",
+ "DefaultValue": "default value",
+ "DisplayName": "display name for attr0",
+ "HelpText": "description for attr0",
+ "MenuPath": "./menu/path/for/attr0",
+ "ReadOnly": false,
+ "Type": "String",
+ "Value": []
+ }
+ ]
+ },
+ "RegistryVersion": "1.0.0"
+}
+
+https://BMC_IPADDR/redfish/v1/Systems/system/Bios/Settings
+{
+ "@odata.id": "/redfish/v1/Systems/system/Bios/Settings",
+ "@odata.type": "#Bios.v1_1_0.Bios",
+ "AttributeRegistry": "BiosAttributeRegistry",
+ "Attributes": {
+ "QuietBoot": "0x0"
+ },
+ "Id": "BiosSettingsV1",
+ "Name": "Bios Settings Version 1"
+}
+
+2. Passed Validator check for bios resource and bios attribute registry
+*** /redfish/v1/Systems/system/Bios
+INFO - Type (#Bios.v1_1_0.Bios), GET SUCCESS (time: 1.57377)
+INFO - PASS
+*** /redfish/v1/Registries/BiosAttributeRegistry
+INFO - Type (#MessageRegistryFile.v1_1_0.MessageRegistryFile), GET SUCCESS (time: 0.075438)
+INFO - PASS
+INFO -
+*** /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry
+INFO - Type (#AttributeRegistry.v1_3_2.AttributeRegistry), GET SUCCESS (time: 0.075751)
+INFO - PASS
+
+@odata.id /redfish/v1/Systems/system/Bios odata Exists PASS
+@odata.type #Settings.v1_3_0.Settings odata Exists PASS
+Links [JSON Object] Bios.v1_1_0.Links Yes complex
+Links.ActiveSoftwareImage Link: /redfish/v1/UpdateService/FirmwareInventory/bios_active link to: SoftwareInventory Yes PASS
+Links.SoftwareImages Array (size: 1) array of: SoftwareInventory Yes ...
+Links.SoftwareImages[0] Link: /redfish/v1/UpdateService/FirmwareInventory/bios_active SoftwareInventory Yes PASS
+Links.Oem - Resource.Oem No Optional
+SoftwareImages@odata.count 1 odata Exists PASS
+AttributeRegistry BiosAttributeRegistry string Yes PASS
+Actions [JSON Object] Bios.v1_0_0.Actions Yes complex
+Actions.#Bios.ResetBios Action - Yes PASS
+Actions.#Bios.ChangePassword Action - Yes PASS
+Attributes [JSON Object] Bios.v1_0_0.Attributes Yes complex
+Attributes.attr0 current value primitive Yes PASS
+Id BIOS string Yes PASS
+Description BIOS Configuration Service string Yes PASS
+Name BIOS Configuration string Yes PASS
+Oem - Resource.Oem No Optional
+@Redfish.Settings [JSON Object] Settings.Settings Yes complex
+@Redfish.Settings.MaintenanceWindowResource - link to: ItemOrCollection No Optional
+@Redfish.Settings.SupportedApplyTimes - string (enum) No Optional
+@Redfish.Settings.Time - date No Optional
+@Redfish.Settings.ETag - string No Optional
+@Redfish.Settings.SettingsObject Link: /redfish/v1/Systems/system/Bios/Settings link to: Item Yes PASS
+@Redfish.Settings.Messages - Message No Optional
+
+@odata.id /redfish/v1/Registries/BiosAttributeRegistry odata Exists PASS
+@odata.type #MessageRegistryFile.v1_1_0.MessageRegistryFile odata Exists PASS
+Languages@odata.count 1 odata Exists PASS
+Location@odata.count 1 odata Exists PASS
+Actions - MessageRegistryFile.v1_1_0.Actions No Optional
+Languages Array (size: 1) string Yes ...
+Languages[0] en string Yes PASS
+Registry BiosAttributeRegistry.1.0.0 string Yes PASS
+Location Array (size: 1) array of: Location Yes ...
+Location[0] [JSON Object] Location Yes complex
+Location[0].Language en string Yes PASS
+Location[0].Uri /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry string Yes PASS
+Location[0].ArchiveUri - string No Optional
+Location[0].PublicationUri - string No Optional
+Location[0].ArchiveFile - string No Optional
+Id BiosAttributeRegistry string Yes PASS
+Description BiosAttributeRegistry Message Registry File Location string Yes PASS
+Name BiosAttributeRegistry Message Registry File string Yes PASS
+Oem - Resource.Oem No Optional
+
+@odata.id /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry odata Exists PASS
+@odata.type #AttributeRegistry.v1_3_2.AttributeRegistry odata Exists PASS
+Actions - AttributeRegistry.v1_1_0.Actions No Optional
+Language en string Yes PASS
+RegistryVersion 1.0.0 string Yes PASS
+OwningEntity OpenBMC string Yes PASS
+SupportedSystems - SupportedSystems No Optional
+RegistryEntries [JSON Object] AttributeRegistry.v1_0_0.RegistryEntries Yes complex
+RegistryEntries.Attributes Array (size: 1) array of: Attributes Yes ...
+RegistryEntries.Attributes[0] [JSON Object] Attributes Yes complex
+RegistryEntries.Attributes[0].Oem - Resource.Oem No Optional
+RegistryEntries.Attributes[0].ResetRequired - boolean No Optional
+RegistryEntries.Attributes[0].UefiDevicePath - string No Optional
+RegistryEntries.Attributes[0].UefiKeywordName - string No Optional
+RegistryEntries.Attributes[0].UefiNamespaceId - string No Optional
+RegistryEntries.Attributes[0].AttributeName attr0 string Yes PASS
+RegistryEntries.Attributes[0].Type String string (enum) Yes PASS
+RegistryEntries.Attributes[0].Value Array (size: 0) array of: AttributeValue Yes ...
+RegistryEntries.Attributes[0].DisplayName display name for attr0 string Yes PASS
+RegistryEntries.Attributes[0].HelpText description for attr0 string Yes PASS
+RegistryEntries.Attributes[0].WarningText - string No Optional
+RegistryEntries.Attributes[0].CurrentValue current value primitive Yes PASS
+RegistryEntries.Attributes[0].DefaultValue default value primitive Yes PASS
+RegistryEntries.Attributes[0].DisplayOrder - number No Optional
+RegistryEntries.Attributes[0].MenuPath ./menu/path/for/attr0 string Yes PASS
+RegistryEntries.Attributes[0].ReadOnly False boolean Yes PASS
+RegistryEntries.Attributes[0].WriteOnly - boolean No Optional
+RegistryEntries.Attributes[0].GrayOut - boolean No Optional
+RegistryEntries.Attributes[0].Hidden - boolean No Optional
+RegistryEntries.Attributes[0].Immutable - boolean No Optional
+RegistryEntries.Attributes[0].IsSystemUniqueProperty - boolean No Optional
+RegistryEntries.Attributes[0].MaxLength - number No Optional
+RegistryEntries.Attributes[0].MinLength - number No Optional
+RegistryEntries.Attributes[0].ScalarIncrement - number No Optional
+RegistryEntries.Attributes[0].UpperBound - number No Optional
+RegistryEntries.Attributes[0].LowerBound - number No Optional
+RegistryEntries.Attributes[0].ValueExpression - string No Optional
+RegistryEntries.Menus - Menus No Optional
+RegistryEntries.Dependencies - Dependencies No Optional
+Id BiosAttributeRegistry string Yes PASS
+Description - string No Optional
+Name Bios Attribute Registry string Yes PASS
+Oem - Resource.Oem No Optional
+
+Change-Id: Iecc61018c350f0b8c89df59b2864b941508b1916
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ redfish-core/include/redfish.hpp | 2 +
+ .../include/registries/bios_registry.hpp | 31 ++
+ redfish-core/lib/bios.hpp | 501 ++++++++++++++++++
+ redfish-core/lib/message_registries.hpp | 9 +-
+ 4 files changed, 542 insertions(+), 1 deletion(-)
+ create mode 100644 redfish-core/include/registries/bios_registry.hpp
+
+diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
+index db58d60..298ebb8 100644
+--- a/redfish-core/include/redfish.hpp
++++ b/redfish-core/include/redfish.hpp
+@@ -156,6 +156,8 @@ class RedfishService
+ nodes.emplace_back(std::make_unique<SystemActionsReset>(app));
+ nodes.emplace_back(std::make_unique<SystemResetActionInfo>(app));
+ nodes.emplace_back(std::make_unique<BiosService>(app));
++ nodes.emplace_back(std::make_unique<BiosSettings>(app));
++ nodes.emplace_back(std::make_unique<BiosAttributeRegistry>(app));
+ nodes.emplace_back(std::make_unique<BiosReset>(app));
+ #ifdef BMCWEB_ENABLE_VM_NBDPROXY
+ nodes.emplace_back(std::make_unique<VirtualMedia>(app));
+diff --git a/redfish-core/include/registries/bios_registry.hpp b/redfish-core/include/registries/bios_registry.hpp
+new file mode 100644
+index 0000000..88ef782
+--- /dev/null
++++ b/redfish-core/include/registries/bios_registry.hpp
+@@ -0,0 +1,31 @@
++/*
++// Copyright (c) 2020 Intel Corporation
++//
++// Licensed under the Apache License, Version 2.0 (the "License");
++// you may not use this file except in compliance with the License.
++// You may obtain a copy of the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS,
++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++// See the License for the specific language governing permissions and
++// limitations under the License.
++*/
++#pragma once
++
++namespace redfish::message_registries::bios
++{
++const Header header = {
++ "Copyright 2020 OpenBMC. All rights reserved.",
++ "#MessageRegistry.v1_4_0.MessageRegistry",
++ "BiosAttributeRegistry.1.0.0",
++ "Bios Attribute Registry",
++ "en",
++ "This registry defines the messages for bios attribute registry.",
++ "BiosAttributeRegistry",
++ "1.0.0",
++ "OpenBMC",
++};
++} // namespace redfish::message_registries::bios
+\ No newline at end of file
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index 0917cc7..cb2b74d 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -3,8 +3,140 @@
+ #include "node.hpp"
+
+ #include <utils/fw_utils.hpp>
++
+ namespace redfish
+ {
++
++/*baseBIOSTable
++map{attributeName,struct{attributeType,readonlyStatus,displayname,
++ description,menuPath,current,default,
++ array{struct{optionstring,optionvalue}}}}
++*/
++using BiosBaseTableType = std::vector<std::pair<
++ std::string,
++ std::tuple<
++ std::string, bool, std::string, std::string, std::string,
++ std::variant<int64_t, std::string>, std::variant<int64_t, std::string>,
++ std::vector<
++ std::tuple<std::string, std::variant<int64_t, std::string>>>>>>;
++using BiosBaseTableItemType = std::pair<
++ std::string,
++ std::tuple<
++ std::string, bool, std::string, std::string, std::string,
++ std::variant<int64_t, std::string>, std::variant<int64_t, std::string>,
++ std::vector<
++ std::tuple<std::string, std::variant<int64_t, std::string>>>>>;
++using OptionsItemType =
++ std::tuple<std::string, std::variant<int64_t, std::string>>;
++
++enum BiosBaseTableIndex
++{
++ biosBaseAttrType = 0,
++ biosBaseReadonlyStatus,
++ biosBaseDisplayName,
++ biosBaseDescription,
++ biosBaseMenuPath,
++ biosBaseCurrValue,
++ biosBaseDefaultValue,
++ biosBaseOptions
++};
++enum OptionsItemIndex
++{
++ optItemType = 0,
++ optItemValue
++};
++/*
++ The Pending attribute name and new value.
++ ex- { {"QuietBoot",Type.Integer, 0x1},
++ { "DdrFreqLimit",Type.String,"2933"}
++ }
++*/
++using PendingAttributesType = std::vector<std::pair<
++ std::string, std::tuple<std::string, std::variant<int64_t, std::string>>>>;
++using PendingAttributesItemType =
++ std::pair<std::string,
++ std::tuple<std::string, std::variant<int64_t, std::string>>>;
++enum PendingAttributesIndex
++{
++ pendingAttrType = 0,
++ pendingAttrValue
++};
++static std::string mapAttrTypeToRedfish(const std::string_view typeDbus)
++{
++ std::string ret;
++ if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager."
++ "AttributeType.Enumeration")
++ {
++ ret = "Enumeration";
++ }
++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.String")
++ {
++ ret = "String";
++ }
++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.Password")
++ {
++ ret = "Password";
++ }
++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.Integer")
++ {
++ ret = "Integer";
++ }
++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.Boolean")
++ {
++ ret = "Boolean";
++ }
++ else
++ {
++ ret = "UNKNOWN";
++ }
++
++ return ret;
++}
++static std::string mapBoundTypeToRedfish(const std::string_view typeDbus)
++{
++ std::string ret;
++ if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.ScalarIncrement")
++ {
++ ret = "ScalarIncrement";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.LowerBound")
++ {
++ ret = "LowerBound";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.UpperBound")
++ {
++ ret = "UpperBound";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.MinStringLength")
++ {
++ ret = "MinStringLength";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.MaxStringLength")
++ {
++ ret = "MaxStringLength";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.OneOf")
++ {
++ ret = "OneOf";
++ }
++ else
++ {
++ ret = "UNKNOWN";
++ }
++
++ return ret;
++}
++
+ /**
+ * BiosService class supports handle get method for bios.
+ */
+@@ -33,6 +165,375 @@ class BiosService : public Node
+ // Get the ActiveSoftwareImage and SoftwareImages
+ fw_util::populateFirmwareInformation(asyncResp, fw_util::biosPurpose,
+ "", true);
++ asyncResp->res.jsonValue["@Redfish.Settings"] = {
++ {"@odata.type", "#Settings.v1_3_0.Settings"},
++ {"SettingsObject",
++ {{"@odata.id", "/redfish/v1/Systems/system/Bios/Settings"}}}};
++ asyncResp->res.jsonValue["AttributeRegistry"] = "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["Attributes"] = {};
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
++ << ec;
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++ const std::string& service = getObjectType.begin()->first;
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](
++ const boost::system::error_code ec,
++ const std::variant<BiosBaseTableType>& retBiosTable) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "getBiosAttributes DBUS error: "
++ << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ const BiosBaseTableType* baseBiosTable =
++ std::get_if<BiosBaseTableType>(&retBiosTable);
++ nlohmann::json& attributesJson =
++ asyncResp->res.jsonValue["Attributes"];
++ if (baseBiosTable == nullptr)
++ {
++ BMCWEB_LOG_ERROR << "baseBiosTable == nullptr ";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ for (const BiosBaseTableItemType& item : *baseBiosTable)
++ {
++ const std::string& key = item.first;
++ const std::string& itemType =
++ std::get<biosBaseAttrType>(item.second);
++ std::string attrType =
++ mapAttrTypeToRedfish(itemType);
++ if (attrType == "String")
++ {
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<biosBaseCurrValue>(
++ item.second));
++ attributesJson.emplace(key, currValue != nullptr
++ ? *currValue
++ : "");
++ }
++ else if (attrType == "Integer")
++ {
++ const int64_t* currValue = std::get_if<int64_t>(
++ &std::get<biosBaseCurrValue>(item.second));
++ attributesJson.emplace(
++ key, currValue != nullptr ? *currValue : 0);
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR
++ << "Unsupported attribute type.";
++ messages::internalError(asyncResp->res);
++ }
++ }
++ },
++ service, "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.BIOSConfig.Manager", "BaseBIOSTable");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/bios_config/manager",
++ std::array<const char*, 0>());
++ }
++};
++
++/**
++ * BiosSettings class supports handle GET/PATCH method for
++ * BIOS configuration pending settings.
++ */
++class BiosSettings : public Node
++{
++ public:
++ BiosSettings(App& app) :
++ Node(app, "/redfish/v1/Systems/system/Bios/Settings")
++ {
++ entityPrivileges = {{boost::beast::http::verb::get, {{"Login"}}}};
++ }
++
++ private:
++ void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const crow::Request&, const std::vector<std::string>&) override
++ {
++ asyncResp->res.jsonValue["@odata.id"] =
++ "/redfish/v1/Systems/system/Bios/Settings";
++ asyncResp->res.jsonValue["@odata.type"] = "#Bios.v1_1_0.Bios";
++ asyncResp->res.jsonValue["Name"] = "Bios Settings Version 1";
++ asyncResp->res.jsonValue["Id"] = "BiosSettingsV1";
++ asyncResp->res.jsonValue["AttributeRegistry"] = "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["Attributes"] = {};
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
++ << ec;
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++ std::string service = getObjectType.begin()->first;
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const std::variant<PendingAttributesType>&
++ retPendingAttributes) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "getBiosSettings DBUS error: "
++ << ec;
++ messages::resourceNotFound(asyncResp->res,
++ "Systems/system/Bios",
++ "Settings");
++ return;
++ }
++ const PendingAttributesType* pendingAttributes =
++ std::get_if<PendingAttributesType>(
++ &retPendingAttributes);
++ nlohmann::json& attributesJson =
++ asyncResp->res.jsonValue["Attributes"];
++ if (pendingAttributes == nullptr)
++ {
++ BMCWEB_LOG_ERROR << "pendingAttributes == nullptr ";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ for (const PendingAttributesItemType& item :
++ *pendingAttributes)
++ {
++ const std::string& key = item.first;
++ const std::string& itemType =
++ std::get<pendingAttrType>(item.second);
++ std::string attrType =
++ mapAttrTypeToRedfish(itemType);
++ if (attrType == "String")
++ {
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<pendingAttrValue>(
++ item.second));
++ attributesJson.emplace(key, currValue != nullptr
++ ? *currValue
++ : "");
++ }
++ else if (attrType == "Integer")
++ {
++ const int64_t* currValue = std::get_if<int64_t>(
++ &std::get<pendingAttrValue>(item.second));
++ attributesJson.emplace(
++ key, currValue != nullptr ? *currValue : 0);
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR
++ << "Unsupported attribute type.";
++ messages::internalError(asyncResp->res);
++ }
++ }
++ },
++ service, "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.BIOSConfig.Manager",
++ "PendingAttributes");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/bios_config/manager",
++ std::array<const char*, 0>());
++ }
++};
++/**
++ * BiosAttributeRegistry class supports handle get method for BIOS attribute
++ * registry.
++ */
++class BiosAttributeRegistry : public Node
++{
++ public:
++ BiosAttributeRegistry(App& app) :
++ Node(app, "/redfish/v1/Registries/BiosAttributeRegistry/"
++ "BiosAttributeRegistry")
++ {
++ entityPrivileges = {{boost::beast::http::verb::get, {{"Login"}}}};
++ }
++
++ private:
++ void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const crow::Request&, const std::vector<std::string>&) override
++ {
++ asyncResp->res.jsonValue["@odata.id"] =
++ "/redfish/v1/Registries/BiosAttributeRegistry/"
++ "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["@odata.type"] =
++ "#AttributeRegistry.v1_3_2.AttributeRegistry";
++ asyncResp->res.jsonValue["Name"] = "Bios Attribute Registry";
++ asyncResp->res.jsonValue["Id"] = "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["RegistryVersion"] = "1.0.0";
++ asyncResp->res.jsonValue["Language"] = "en";
++ asyncResp->res.jsonValue["OwningEntity"] = "OpenBMC";
++ asyncResp->res.jsonValue["RegistryEntries"]["Attributes"] =
++ nlohmann::json::array();
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
++ << ec;
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++ std::string service = getObjectType.begin()->first;
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](
++ const boost::system::error_code ec,
++ const std::variant<BiosBaseTableType>& retBiosTable) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR
++ << "getBiosAttributeRegistry DBUS error: "
++ << ec;
++ messages::resourceNotFound(
++ asyncResp->res, "Registries/Bios", "Bios");
++ return;
++ }
++ const BiosBaseTableType* baseBiosTable =
++ std::get_if<BiosBaseTableType>(&retBiosTable);
++ nlohmann::json& attributeArray =
++ asyncResp->res
++ .jsonValue["RegistryEntries"]["Attributes"];
++ nlohmann::json optionsArray = nlohmann::json::array();
++ if (baseBiosTable == nullptr)
++ {
++ BMCWEB_LOG_ERROR << "baseBiosTable == nullptr ";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ for (const BiosBaseTableItemType& item : *baseBiosTable)
++ {
++ const std::string& itemType =
++ std::get<biosBaseAttrType>(item.second);
++ std::string attrType =
++ mapAttrTypeToRedfish(itemType);
++ if (attrType == "UNKNOWN")
++ {
++ BMCWEB_LOG_ERROR << "attrType == UNKNOWN";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ nlohmann::json attributeItem;
++ attributeItem["AttributeName"] = item.first;
++ attributeItem["Type"] = attrType;
++ attributeItem["ReadOnly"] =
++ std::get<biosBaseReadonlyStatus>(item.second);
++ attributeItem["DisplayName"] =
++ std::get<biosBaseDisplayName>(item.second);
++ attributeItem["HelpText"] =
++ std::get<biosBaseDescription>(item.second);
++ attributeItem["MenuPath"] =
++ std::get<biosBaseMenuPath>(item.second);
++
++ if (attrType == "String")
++ {
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<biosBaseCurrValue>(
++ item.second));
++ const std::string* defValue =
++ std::get_if<std::string>(
++ &std::get<biosBaseDefaultValue>(
++ item.second));
++ attributeItem["CurrentValue"] =
++ currValue != nullptr ? *currValue : "";
++ attributeItem["DefaultValue"] =
++ defValue != nullptr ? *defValue : "";
++ }
++ else if (attrType == "Integer")
++ {
++ const int64_t* currValue = std::get_if<int64_t>(
++ &std::get<biosBaseCurrValue>(item.second));
++ const int64_t* defValue = std::get_if<int64_t>(
++ &std::get<biosBaseDefaultValue>(
++ item.second));
++ attributeItem["CurrentValue"] =
++ currValue != nullptr ? *currValue : 0;
++ attributeItem["DefaultValue"] =
++ defValue != nullptr ? *defValue : 0;
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR
++ << "Unsupported attribute type.";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ const std::vector<OptionsItemType>& optionsVector =
++ std::get<biosBaseOptions>(item.second);
++ for (const OptionsItemType& optItem : optionsVector)
++ {
++ nlohmann::json optItemJson;
++ const std::string& strOptItemType =
++ std::get<optItemType>(optItem);
++ std::string optItemTypeRedfish =
++ mapBoundTypeToRedfish(strOptItemType);
++ if (optItemTypeRedfish == "UNKNOWN")
++ {
++ BMCWEB_LOG_ERROR
++ << "optItemTypeRedfish == UNKNOWN";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ if (optItemTypeRedfish == "OneOf")
++ {
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<optItemValue>(optItem));
++ optItemJson[optItemTypeRedfish] =
++ currValue != nullptr ? *currValue : "";
++ }
++ else
++ {
++ const int64_t* currValue =
++ std::get_if<int64_t>(
++ &std::get<optItemValue>(optItem));
++ optItemJson[optItemTypeRedfish] =
++ currValue != nullptr ? *currValue : 0;
++ }
++
++ optionsArray.push_back(optItemJson);
++ }
++
++ attributeItem["Value"] = optionsArray;
++ attributeArray.push_back(attributeItem);
++ }
++ },
++ service, "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.BIOSConfig.Manager", "BaseBIOSTable");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/bios_config/manager",
++ std::array<const char*, 0>());
+ }
+ };
+ /**
+diff --git a/redfish-core/lib/message_registries.hpp b/redfish-core/lib/message_registries.hpp
+index 455bf70..7afbfc2 100644
+--- a/redfish-core/lib/message_registries.hpp
++++ b/redfish-core/lib/message_registries.hpp
+@@ -18,6 +18,7 @@
+ #include "node.hpp"
+ #include "registries.hpp"
+ #include "registries/base_message_registry.hpp"
++#include "registries/bios_registry.hpp"
+ #include "registries/openbmc_message_registry.hpp"
+ #include "registries/resource_event_message_registry.hpp"
+ #include "registries/task_event_message_registry.hpp"
+@@ -56,11 +57,12 @@ class MessageRegistryFileCollection : public Node
+ {"@odata.id", "/redfish/v1/Registries"},
+ {"Name", "MessageRegistryFile Collection"},
+ {"Description", "Collection of MessageRegistryFiles"},
+- {"Members@odata.count", 4},
++ {"Members@odata.count", 5},
+ {"Members",
+ {{{"@odata.id", "/redfish/v1/Registries/Base"}},
+ {{"@odata.id", "/redfish/v1/Registries/TaskEvent"}},
+ {{"@odata.id", "/redfish/v1/Registries/ResourceEvent"}},
++ {{"@odata.id", "/redfish/v1/Registries/BiosAttributeRegistry"}},
+ {{"@odata.id", "/redfish/v1/Registries/OpenBMC"}}}}};
+ }
+ };
+@@ -116,6 +118,11 @@ class MessageRegistryFile : public Node
+ header = &message_registries::resource_event::header;
+ url = message_registries::resource_event::url;
+ }
++ else if (registry == "BiosAttributeRegistry")
++ {
++ header = &message_registries::bios::header;
++ dmtf.clear();
++ }
+ else
+ {
+ messages::resourceNotFound(
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0002-BaseBiosTable-Add-support-for-PATCH-operation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0002-BaseBiosTable-Add-support-for-PATCH-operation.patch
new file mode 100644
index 000000000..21a21e8db
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0002-BaseBiosTable-Add-support-for-PATCH-operation.patch
@@ -0,0 +1,152 @@
+From 9c498d683be59ce25dd0124ba7ec5e026c59bbbf Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Wed, 23 Dec 2020 16:50:45 +0800
+Subject: [PATCH] BaseBiosTable: Add support for PATCH operation
+
+This commit brings in support for PATCH operation of the
+bios variables that updates the BaseBiosTable.
+
+Tested-By:
+* Passed Redfish validator
+
+* Single Attribute:
+PATCH https://${bmc}/redfish/v1/Systems/system/Bios/Settings -d
+'{"data":[{"AttributeName": <attribute name>, "AttributeType":
+<attribute type>, "AttributeValue": <attribute value>}]}'
+
+* Multiple Attributes:
+PATCH https://${bmc}/redfish/v1/Systems/system/Bios/Settings -d
+'{"data":[{"AttributeName": <attribute name>, "AttributeType":
+<attribute type>, "AttributeValue": <attribute value>},
+{"AttributeName": <attribute name>, "AttributeType":
+<attribute type>, "AttributeValue": <attribute value>}]}'
+
+This makes use of the "Set" of "PendingAttributes" in the
+backend and that updates the BaseBiosTable.
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ redfish-core/lib/bios.hpp | 93 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 92 insertions(+), 1 deletion(-)
+
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index cb2b74d..860a643 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -96,6 +96,29 @@ static std::string mapAttrTypeToRedfish(const std::string_view typeDbus)
+
+ return ret;
+ }
++static std::string mapRedfishToAttrType(const std::string_view type)
++{
++ std::string ret;
++ if (type == "string")
++ {
++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String";
++ }
++ else if (type == "int")
++ {
++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer";
++ }
++ else if (type == "enum")
++ {
++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType."
++ "Enumeration";
++ }
++ else
++ {
++ ret = "UNKNOWN";
++ }
++
++ return ret;
++}
+ static std::string mapBoundTypeToRedfish(const std::string_view typeDbus)
+ {
+ std::string ret;
+@@ -260,7 +283,9 @@ class BiosSettings : public Node
+ BiosSettings(App& app) :
+ Node(app, "/redfish/v1/Systems/system/Bios/Settings")
+ {
+- entityPrivileges = {{boost::beast::http::verb::get, {{"Login"}}}};
++ entityPrivileges = {
++ {boost::beast::http::verb::get, {{"Login"}}},
++ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}};
+ }
+
+ private:
+@@ -356,6 +381,72 @@ class BiosSettings : public Node
+ "/xyz/openbmc_project/bios_config/manager",
+ std::array<const char*, 0>());
+ }
++
++ void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const crow::Request& req,
++ const std::vector<std::string>&) override
++ {
++ nlohmann::json inpJson;
++
++ if (!redfish::json_util::readJson(req, asyncResp->res, "data", inpJson))
++ {
++ return;
++ }
++
++ for (auto& attrInfo : inpJson)
++ {
++ std::optional<std::string> attrName;
++ std::optional<std::string> attrType;
++ std::optional<std::string> attrValue;
++ if (!json_util::getValueFromJsonObject(attrInfo, "AttributeName",
++ attrName))
++ {
++ messages::propertyMissing(asyncResp->res, "AttributeName");
++ return;
++ }
++ if (!json_util::getValueFromJsonObject(attrInfo, "AttributeType",
++ attrType))
++ {
++ messages::propertyMissing(asyncResp->res, "AttributeType");
++ return;
++ }
++ if (!json_util::getValueFromJsonObject(attrInfo, "AttributeValue",
++ attrValue))
++ {
++ messages::propertyMissing(asyncResp->res, "AttributeValue");
++ return;
++ }
++ std::string biosAttrType = mapRedfishToAttrType(*attrType);
++
++ if (biosAttrType == "UNKNOWN")
++ {
++ BMCWEB_LOG_ERROR << "Invalid attribute type";
++ messages::propertyValueNotInList(asyncResp->res,
++ "AttributeType", *attrType);
++ return;
++ }
++
++ PendingAttributesType pendingAttributes;
++ pendingAttributes.emplace_back(std::make_pair(
++ *attrName, std::make_tuple(biosAttrType, *attrValue)));
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "doPatch resp_handler got error "
++ << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ },
++ "xyz.openbmc_project.BIOSConfigManager",
++ "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Set",
++ "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes",
++ std::variant<PendingAttributesType>(pendingAttributes));
++ }
++ }
+ };
+ /**
+ * BiosAttributeRegistry class supports handle get method for BIOS attribute
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0003-Add-support-to-ResetBios-action.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0003-Add-support-to-ResetBios-action.patch
new file mode 100644
index 000000000..5a24996a0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0003-Add-support-to-ResetBios-action.patch
@@ -0,0 +1,61 @@
+From 4e85ce8a5f34038c289504855d21ebfa3d6b94f0 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Wed, 23 Dec 2020 22:47:56 +0800
+Subject: [PATCH] Add support to ResetBios action
+
+Tested:
+
+Bios reset flag can be modified throw redfish
+POST https://IP_ADDR/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios
+
+Change-Id: I5e5fbdd70d4a3ce3b976cc2eb0a7d9a2a3adb124
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ redfish-core/lib/bios.hpp | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index 860a643..1eb7bef 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -638,7 +638,7 @@ class BiosReset : public Node
+ Node(app, "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios/")
+ {
+ entityPrivileges = {
+- {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
++ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ }
+
+ private:
+@@ -649,19 +649,24 @@ class BiosReset : public Node
+ void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const crow::Request&, const std::vector<std::string>&) override
+ {
++ std::string resetFlag =
++ "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag.FactoryDefaults";
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+ {
+- BMCWEB_LOG_ERROR << "Failed to reset bios: " << ec;
++ BMCWEB_LOG_ERROR << "doPost bios reset got error " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
++ BMCWEB_LOG_DEBUG << "bios reset action is done";
+ },
+- "org.open_power.Software.Host.Updater",
+- "/xyz/openbmc_project/software",
+- "xyz.openbmc_project.Common.FactoryReset", "Reset");
++ "xyz.openbmc_project.BIOSConfigManager",
++ "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Set",
++ "xyz.openbmc_project.BIOSConfig.Manager", "ResetBIOSSettings",
++ std::variant<std::string>(resetFlag));
+ }
+ };
+ } // namespace redfish
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0004-Add-support-to-ChangePassword-action.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0004-Add-support-to-ChangePassword-action.patch
new file mode 100644
index 000000000..e87995aca
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0004-Add-support-to-ChangePassword-action.patch
@@ -0,0 +1,139 @@
+From 0ce94f6caf5d76d7f1abc71f6f8f7dc320517984 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Wed, 23 Dec 2020 14:41:23 +0800
+Subject: [PATCH] Add support to ChangePassword action
+
+Tested:
+
+Passed Redfish validator.
+Bios change password:
+root@intel-obmc:~# cat /var/lib/bios-settings-manager/seedData
+{
+"UserPwdHash": "08D91157785366CDC3AA64D87E5E3C621EDAB13E26B6E484397EBA5E459E54C567BF5B1FFB36A43B6142B18F8D642E9D",
+"AdminPwdHash": "08D91157785366CDC3AA64D87E5E3C621EDAB13E26B6E484397EBA5E459E54C567BF5B1FFB36A43B6142B18F8D642E9D",
+"Seed": "123456",
+"HashAlgo": "SHA384"
+}
+POST https://IP_ADDR/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword
+{
+ "NewPassword": "12345678",
+ "OldPassword": "1234567890",
+ "PasswordName": "Administrator"
+}
+root@intel-obmc:~# cat /var/lib/bios-settings-manager/passwordData
+{
+ "CurrentPassword": "1234567890",
+ "IsAdminPwdChanged": 1,
+ "IsUserPwdChanged": 0,
+ "NewPassword": "2DD65D57EB60B1D92C5F3D2DC84724FCEE7BC02E57AA75E834712266ED94CAC704047B2FF7CEC1C36BED280B36BB5AC6",
+ "UserName": "Administrator"
+}
+
+Change-Id: I90319a68da0b0a7f9c5cd65a8cb8cf52269a5f52
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ redfish-core/include/redfish.hpp | 1 +
+ redfish-core/lib/bios.hpp | 70 ++++++++++++++++++++++++++++++++
+ 2 files changed, 71 insertions(+)
+
+diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
+index 298ebb8..4418c3d 100644
+--- a/redfish-core/include/redfish.hpp
++++ b/redfish-core/include/redfish.hpp
+@@ -159,6 +159,7 @@ class RedfishService
+ nodes.emplace_back(std::make_unique<BiosSettings>(app));
+ nodes.emplace_back(std::make_unique<BiosAttributeRegistry>(app));
+ nodes.emplace_back(std::make_unique<BiosReset>(app));
++ nodes.emplace_back(std::make_unique<BiosChangePassword>(app));
+ #ifdef BMCWEB_ENABLE_VM_NBDPROXY
+ nodes.emplace_back(std::make_unique<VirtualMedia>(app));
+ nodes.emplace_back(std::make_unique<VirtualMediaCollection>(app));
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index 1eb7bef..12ec472 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -184,6 +184,9 @@ class BiosService : public Node
+ asyncResp->res.jsonValue["Actions"]["#Bios.ResetBios"] = {
+ {"target",
+ "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios"}};
++ asyncResp->res.jsonValue["Actions"]["#Bios.ChangePassword"] = {
++ {"target",
++ "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword"}};
+
+ // Get the ActiveSoftwareImage and SoftwareImages
+ fw_util::populateFirmwareInformation(asyncResp, fw_util::biosPurpose,
+@@ -669,4 +672,71 @@ class BiosReset : public Node
+ std::variant<std::string>(resetFlag));
+ }
+ };
++
++/**
++ * BiosChangePassword class supports handle POST method for change bios
++ * password. The class retrieves and sends data directly to D-Bus.
++ */
++class BiosChangePassword : public Node
++{
++ public:
++ BiosChangePassword(App& app) :
++ Node(app,
++ "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword/")
++ {
++ entityPrivileges = {
++ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
++ }
++
++ private:
++ /**
++ * Function handles POST method request.
++ * Analyzes POST body message before sends Reset request data to D-Bus.
++ */
++ void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const crow::Request& req,
++ const std::vector<std::string>&) override
++ {
++ std::string currentPassword, newPassword, userName;
++ if (!json_util::readJson(req, asyncResp->res, "NewPassword",
++ newPassword, "OldPassword", currentPassword,
++ "PasswordName", userName))
++ {
++ return;
++ }
++ if (currentPassword.empty())
++ {
++ messages::actionParameterUnknown(asyncResp->res, "ChangePassword",
++ "OldPassword");
++ return;
++ }
++ if (newPassword.empty())
++ {
++ messages::actionParameterUnknown(asyncResp->res, "ChangePassword",
++ "NewPassword");
++ return;
++ }
++ if (userName.empty())
++ {
++ messages::actionParameterUnknown(asyncResp->res, "ChangePassword",
++ "PasswordName");
++ return;
++ }
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_CRITICAL
++ << "Failed in doPost(BiosChangePassword) " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ },
++ "xyz.openbmc_project.BIOSConfigPassword",
++ "/xyz/openbmc_project/bios_config/password",
++ "xyz.openbmc_project.BIOSConfig.Password", "ChangePassword",
++ userName, currentPassword, newPassword);
++ }
++};
++
+ } // namespace redfish
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0005-Fix-remove-bios-user-pwd-change-option-via-Redfish.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0005-Fix-remove-bios-user-pwd-change-option-via-Redfish.patch
new file mode 100644
index 000000000..75a78abb4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0005-Fix-remove-bios-user-pwd-change-option-via-Redfish.patch
@@ -0,0 +1,44 @@
+From fedcdb7887b4d934ee763d75f7988825300c5cef Mon Sep 17 00:00:00 2001
+From: Ayushi Smriti <smriti.ayushi@intel.com>
+Date: Thu, 6 May 2021 11:56:38 +0530
+Subject: [PATCH] Fix:remove bios user pwd change option via Redfish
+
+BMC should not provide user bios setup password change option via
+Redfish as per bios security requirements. Only Admin BIOS setup
+password is supported.
+
+Added check for the password name action parameter and
+do not allow if it has User Password value from redfish side.
+
+Tested: sent POST query in redfish on URI:
+https://<ip>/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword
+error occurs for UserPassword parameter and allows for AdminPassword.
+
+Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com>
+---
+ redfish-core/lib/bios.hpp | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index 12ec472..0416934 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -722,6 +722,15 @@ class BiosChangePassword : public Node
+ "PasswordName");
+ return;
+ }
++
++ // In Intel BIOS, we are not supporting user password in BIOS setup
++ if (userName == "UserPassword")
++ {
++ messages::actionParameterUnknown(asyncResp->res, "ChangePassword",
++ "PasswordName");
++ return;
++ }
++
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket
new file mode 100644
index 000000000..8782e4dd3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket
@@ -0,0 +1,9 @@
+[Unit]
+Description=BMC Webserver socket
+
+[Socket]
+ListenStream=443
+ReusePort=true
+
+[Install]
+WantedBy=sockets.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-EventService-Fix-retry-handling-for-http-client.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-EventService-Fix-retry-handling-for-http-client.patch
new file mode 100644
index 000000000..bda893a81
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-EventService-Fix-retry-handling-for-http-client.patch
@@ -0,0 +1,547 @@
+From 3d6c3b3e91c04ff8f10bff49bcf2a7d7206c53df Mon Sep 17 00:00:00 2001
+From: Sunitha Harish <sunithaharish04@gmail.com>
+Date: Fri, 19 Feb 2021 13:38:31 +0530
+Subject: [PATCH] EventService : Fix retry handling for http-client
+
+When the event send/receive is failed, the bmcweb does not handle
+the failure to tear-down the complete connection and start a fresh
+
+The keep-alive header from the event listener is read to update
+the connection states, so that the connection will be kept alive
+or closed as per the subscriber's specifications
+
+Updated the connection state machine to handle retry logic properly.
+Avoided multiple simultaneous async calls which crashes the bmcweb. So
+added connBusy flag which protects simultaneous async calls.
+
+Used boost http response parser as parser for producing the response
+message. Set the parser skip option to handle the empty response message
+from listening server.
+
+Tested by:
+ - Subscribe for the events at BMC using DMTF event listener
+ - Generate an event and see the same is received at the listener's console
+ - Update the listner to change the keep-alive to true/false and
+ observe the http-client connection states at bmcweb
+ - Changed listener client to return non success HTTP status code
+ and observed retry logic gets trigrred in http-client.
+ - Gave wrong fqdn and observed async resolve failure and retry logc.
+ - Stopped listener after connect and verified timeouts on http-client
+ side.
+
+Change-Id: Ibb45691f139916ba2954da37beda9d4f91c7cef3
+Signed-off-by: Sunitha Harish <sunithaharish04@gmail.com>
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+---
+ http/http_client.hpp | 288 ++++++++++--------
+ .../include/event_service_manager.hpp | 2 +-
+ 2 files changed, 162 insertions(+), 128 deletions(-)
+
+diff --git a/http/http_client.hpp b/http/http_client.hpp
+index 992ac2b..feabbba 100644
+--- a/http/http_client.hpp
++++ b/http/http_client.hpp
+@@ -34,22 +34,28 @@ namespace crow
+ {
+
+ static constexpr uint8_t maxRequestQueueSize = 50;
++static constexpr unsigned int httpReadBodyLimit = 8192;
+
+ enum class ConnState
+ {
+ initialized,
+ resolveInProgress,
+ resolveFailed,
++ resolved,
+ connectInProgress,
+ connectFailed,
+ connected,
+ sendInProgress,
+ sendFailed,
++ recvInProgress,
+ recvFailed,
+ idle,
+- suspended,
++ closeInProgress,
+ closed,
+- terminated
++ suspended,
++ terminated,
++ abortConnection,
++ retry
+ };
+
+ class HttpClient : public std::enable_shared_from_this<HttpClient>
+@@ -58,11 +64,13 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ crow::async_resolve::Resolver resolver;
+ boost::beast::tcp_stream conn;
+ boost::asio::steady_timer timer;
+- boost::beast::flat_buffer buffer;
++ boost::beast::flat_static_buffer<httpReadBodyLimit> buffer;
+ boost::beast::http::request<boost::beast::http::string_body> req;
+- boost::beast::http::response<boost::beast::http::string_body> res;
+- std::vector<std::pair<std::string, std::string>> headers;
+- std::queue<std::string> requestDataQueue;
++ std::optional<
++ boost::beast::http::response_parser<boost::beast::http::string_body>>
++ parser;
++ boost::circular_buffer_space_optimized<std::string> requestDataQueue{};
++ std::vector<boost::asio::ip::tcp::endpoint> endPoints;
+ ConnState state;
+ std::string subId;
+ std::string host;
+@@ -76,12 +84,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+
+ void doResolve()
+ {
+- if (state == ConnState::resolveInProgress)
+- {
+- return;
+- }
+ state = ConnState::resolveInProgress;
+-
+ BMCWEB_LOG_DEBUG << "Trying to resolve: " << host << ":" << port;
+
+ auto respHandler =
+@@ -89,78 +92,56 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ const boost::beast::error_code ec,
+ const std::vector<boost::asio::ip::tcp::endpoint>&
+ endpointList) {
+- if (ec)
++ if (ec || (endpointList.size() == 0))
+ {
+ BMCWEB_LOG_ERROR << "Resolve failed: " << ec.message();
+ self->state = ConnState::resolveFailed;
+- self->checkQueue();
++ self->handleConnState();
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "Resolved";
+- self->doConnect(endpointList);
++ self->endPoints.assign(endpointList.begin(),
++ endpointList.end());
++ self->state = ConnState::resolved;
++ self->handleConnState();
+ };
+ resolver.asyncResolve(host, port, std::move(respHandler));
+ }
+
+- void doConnect(
+- const std::vector<boost::asio::ip::tcp::endpoint>& endpointList)
++ void doConnect()
+ {
+- if (state == ConnState::connectInProgress)
+- {
+- return;
+- }
+ state = ConnState::connectInProgress;
+
+ BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port;
+
+ conn.expires_after(std::chrono::seconds(30));
+ conn.async_connect(
+- endpointList, [self(shared_from_this())](
+- const boost::beast::error_code ec,
+- const boost::asio::ip::tcp::endpoint& endpoint) {
++ endPoints, [self(shared_from_this())](
++ const boost::beast::error_code ec,
++ const boost::asio::ip::tcp::endpoint& endpoint) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Connect " << endpoint
+ << " failed: " << ec.message();
+ self->state = ConnState::connectFailed;
+- self->checkQueue();
++ self->handleConnState();
+ return;
+ }
+- self->state = ConnState::connected;
+ BMCWEB_LOG_DEBUG << "Connected to: " << endpoint;
+-
+- self->checkQueue();
++ self->state = ConnState::connected;
++ self->handleConnState();
+ });
+ }
+
+ void sendMessage(const std::string& data)
+ {
+- if (state == ConnState::sendInProgress)
+- {
+- return;
+- }
+ state = ConnState::sendInProgress;
+
+ BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port;
+
+- req.version(static_cast<int>(11)); // HTTP 1.1
+- req.target(uri);
+- req.method(boost::beast::http::verb::post);
+-
+- // Set headers
+- for (const auto& [key, value] : headers)
+- {
+- req.set(key, value);
+- }
+- req.set(boost::beast::http::field::host, host);
+- req.keep_alive(true);
+-
+ req.body() = data;
+ req.prepare_payload();
+
+- // Set a timeout on the operation
+- conn.expires_after(std::chrono::seconds(30));
+-
+ // Send the HTTP request to the remote host
+ boost::beast::http::async_write(
+ conn, req,
+@@ -171,7 +152,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ BMCWEB_LOG_ERROR << "sendMessage() failed: "
+ << ec.message();
+ self->state = ConnState::sendFailed;
+- self->checkQueue();
++ self->handleConnState();
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: "
+@@ -184,9 +165,17 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+
+ void recvMessage()
+ {
++ state = ConnState::recvInProgress;
++
++ parser.emplace(std::piecewise_construct, std::make_tuple());
++ parser->body_limit(httpReadBodyLimit);
++
++ // Check only for the response header
++ parser->skip(true);
++
+ // Receive the HTTP response
+ boost::beast::http::async_read(
+- conn, buffer, res,
++ conn, buffer, *parser,
+ [self(shared_from_this())](const boost::beast::error_code& ec,
+ const std::size_t& bytesTransferred) {
+ if (ec)
+@@ -194,30 +183,47 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ BMCWEB_LOG_ERROR << "recvMessage() failed: "
+ << ec.message();
+ self->state = ConnState::recvFailed;
+- self->checkQueue();
++ self->handleConnState();
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: "
+ << bytesTransferred;
+- boost::ignore_unused(bytesTransferred);
+-
+- // Discard received data. We are not interested.
+- BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res;
++ BMCWEB_LOG_DEBUG << "recvMessage() data: "
++ << self->parser->get();
+
+ // Send is successful, Lets remove data from queue
+ // check for next request data in queue.
+- self->requestDataQueue.pop();
++ if (!self->requestDataQueue.empty())
++ {
++ self->requestDataQueue.pop_front();
++ }
+ self->state = ConnState::idle;
+- self->checkQueue();
++
++ // Keep the connection alive if server supports it
++ // Else close the connection
++ BMCWEB_LOG_DEBUG << "recvMessage() keepalive : "
++ << self->parser->keep_alive();
++ if (!self->parser->keep_alive())
++ {
++ // Abort the connection since server is not keep-alive
++ // enabled
++ self->state = ConnState::abortConnection;
++ }
++
++ // Returns ownership of the parsed message
++ self->parser->release();
++
++ self->handleConnState();
+ });
+ }
+
+ void doClose()
+ {
++ state = ConnState::closeInProgress;
+ boost::beast::error_code ec;
+ conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
++ conn.close();
+
+- state = ConnState::closed;
+ // not_connected happens sometimes so don't bother reporting it.
+ if (ec && ec != boost::beast::errc::not_connected)
+ {
+@@ -225,112 +231,139 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "Connection closed gracefully";
+- }
+-
+- void checkQueue(const bool newRecord = false)
+- {
+- if (requestDataQueue.empty())
++ if ((state != ConnState::suspended) && (state != ConnState::terminated))
+ {
+- // TODO: Having issue in keeping connection alive. So lets close if
+- // nothing to be transferred.
+- doClose();
+-
+- BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n";
+- return;
++ state = ConnState::closed;
++ handleConnState();
+ }
++ }
+
++ void waitAndRetry()
++ {
+ if (retryCount >= maxRetryAttempts)
+ {
+- BMCWEB_LOG_ERROR << "Maximum number of retries is reached.";
++ BMCWEB_LOG_ERROR << "Maximum number of retries reached.";
+
+ // Clear queue.
+ while (!requestDataQueue.empty())
+ {
+- requestDataQueue.pop();
++ requestDataQueue.pop_front();
+ }
+
+- BMCWEB_LOG_DEBUG << "Retry policy is set to " << retryPolicyAction;
++ BMCWEB_LOG_DEBUG << "Retry policy: " << retryPolicyAction;
+ if (retryPolicyAction == "TerminateAfterRetries")
+ {
+ // TODO: delete subscription
+ state = ConnState::terminated;
+- return;
+ }
+ if (retryPolicyAction == "SuspendRetries")
+ {
+ state = ConnState::suspended;
+- return;
+ }
+- // keep retrying, reset count and continue.
++ // Reset the retrycount to zero so that client can try connecting
++ // again if needed
+ retryCount = 0;
++ handleConnState();
++ return;
+ }
+
+- if ((state == ConnState::connectFailed) ||
+- (state == ConnState::sendFailed) ||
+- (state == ConnState::recvFailed))
++ if (runningTimer)
+ {
+- if (newRecord)
+- {
+- // We are already running async wait and retry.
+- // Since record is added to queue, it gets the
+- // turn in FIFO.
+- return;
+- }
+-
+- if (runningTimer)
+- {
+- BMCWEB_LOG_DEBUG << "Retry timer is already running.";
+- return;
+- }
+- runningTimer = true;
+-
+- retryCount++;
+-
+- BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs
+- << " seconds. RetryCount = " << retryCount;
+- timer.expires_after(std::chrono::seconds(retryIntervalSecs));
+- timer.async_wait(
+- [self = shared_from_this()](const boost::system::error_code&) {
+- self->runningTimer = false;
+- self->connStateCheck();
+- });
++ BMCWEB_LOG_DEBUG << "Retry timer is already running.";
+ return;
+ }
+- // reset retry count.
+- retryCount = 0;
+- connStateCheck();
++ runningTimer = true;
++
++ retryCount++;
++
++ BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs
++ << " seconds. RetryCount = " << retryCount;
++ timer.expires_after(std::chrono::seconds(retryIntervalSecs));
++ timer.async_wait(
++ [self = shared_from_this()](const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "async_wait failed: " << ec.message();
++ // Ignore the error and continue the retry loop to attempt
++ // sending the event as per the retry policy
++ }
++ self->runningTimer = false;
+
++ // Lets close connection and start from resolve.
++ self->doClose();
++ });
+ return;
+ }
+
+- void connStateCheck()
++ void handleConnState()
+ {
+ switch (state)
+ {
+ case ConnState::resolveInProgress:
+ case ConnState::connectInProgress:
+ case ConnState::sendInProgress:
+- case ConnState::suspended:
+- case ConnState::terminated:
+- // do nothing
++ case ConnState::recvInProgress:
++ case ConnState::closeInProgress:
++ {
++ BMCWEB_LOG_DEBUG << "Async operation is already in progress";
+ break;
++ }
+ case ConnState::initialized:
+ case ConnState::closed:
++ {
++ if (requestDataQueue.empty())
++ {
++ BMCWEB_LOG_DEBUG << "requestDataQueue is empty";
++ return;
++ }
++ doResolve();
++ break;
++ }
++ case ConnState::resolved:
++ {
++ doConnect();
++ break;
++ }
++ case ConnState::suspended:
++ case ConnState::terminated:
++ {
++ doClose();
++ break;
++ }
++ case ConnState::resolveFailed:
+ case ConnState::connectFailed:
+ case ConnState::sendFailed:
+ case ConnState::recvFailed:
+- case ConnState::resolveFailed:
++ case ConnState::retry:
+ {
+- doResolve();
++ // In case of failures during connect and handshake
++ // the retry policy will be applied
++ waitAndRetry();
+ break;
+ }
+ case ConnState::connected:
+ case ConnState::idle:
+ {
++ // State idle means, previous attempt is successful
++ // State connected means, client connection is established
++ // successfully
++ if (requestDataQueue.empty())
++ {
++ BMCWEB_LOG_DEBUG << "requestDataQueue is empty";
++ return;
++ }
+ std::string data = requestDataQueue.front();
+ sendMessage(data);
+ break;
+ }
++ case ConnState::abortConnection:
++ {
++ // Server did not want to keep alive the session
++ doClose();
++ break;
++ }
++ default:
++ break;
+ }
+ }
+
+@@ -339,37 +372,38 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ const std::string& destIP, const std::string& destPort,
+ const std::string& destUri) :
+ conn(ioc),
+- timer(ioc), subId(id), host(destIP), port(destPort), uri(destUri),
+- retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0),
++ timer(ioc), req(boost::beast::http::verb::post, destUri, 11),
++ state(ConnState::initialized), subId(id), host(destIP), port(destPort),
++ uri(destUri), retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0),
+ retryPolicyAction("TerminateAfterRetries"), runningTimer(false)
+ {
+- state = ConnState::initialized;
++ // Set the request header
++ req.set(boost::beast::http::field::host, host);
++ req.set(boost::beast::http::field::content_type, "application/json");
++ req.keep_alive(true);
++
++ requestDataQueue.set_capacity(maxRequestQueueSize);
+ }
+
+ void sendData(const std::string& data)
+ {
+- if (state == ConnState::suspended)
++ if ((state == ConnState::suspended) || (state == ConnState::terminated))
+ {
+ return;
+ }
+-
+- if (requestDataQueue.size() <= maxRequestQueueSize)
+- {
+- requestDataQueue.push(data);
+- checkQueue(true);
+- }
+- else
+- {
+- BMCWEB_LOG_ERROR << "Request queue is full. So ignoring data.";
+- }
+-
++ requestDataQueue.push_back(data);
++ handleConnState();
+ return;
+ }
+
+- void setHeaders(
++ void addHeaders(
+ const std::vector<std::pair<std::string, std::string>>& httpHeaders)
+ {
+- headers = httpHeaders;
++ // Set custom headers
++ for (const auto& [key, value] : httpHeaders)
++ {
++ req.set(key, value);
++ }
+ }
+
+ void setRetryConfig(const uint32_t retryAttempts,
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index fa4e41a..c999121 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -423,7 +423,7 @@ class Subscription
+ reqHeaders.emplace_back(std::pair(key, val));
+ }
+ }
+- conn->setHeaders(reqHeaders);
++ conn->addHeaders(reqHeaders);
+ conn->sendData(msg);
+ this->eventSeqNum++;
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch
new file mode 100644
index 000000000..7cbb406a5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch
@@ -0,0 +1,402 @@
+From 5f19e5c8ebc5cb0ce331e4ef841526995b6bdb2e Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Mon, 22 Feb 2021 17:07:47 +0000
+Subject: [PATCH] EventService: https client support
+
+Add https client support for push style
+eventing. Using this BMC can push the event
+logs/telemetry data to event listener over
+secure http channel.
+
+Tested:
+ - Created subscription with https destination
+ url. Using SubmitTestEvent action set the
+ event and can see event on event listener.
+ - Validator passed.
+
+Change-Id: I44c3918b39baa2eb5fddda9d635f99aa280a422a
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+---
+ http/http_client.hpp | 257 ++++++++++++------
+ .../include/event_service_manager.hpp | 2 +-
+ 2 files changed, 176 insertions(+), 83 deletions(-)
+
+diff --git a/http/http_client.hpp b/http/http_client.hpp
+index feabbba..aaf1b2d 100644
+--- a/http/http_client.hpp
++++ b/http/http_client.hpp
+@@ -20,6 +20,7 @@
+ #include <boost/beast/core/flat_buffer.hpp>
+ #include <boost/beast/core/tcp_stream.hpp>
+ #include <boost/beast/http/message.hpp>
++#include <boost/beast/ssl/ssl_stream.hpp>
+ #include <boost/beast/version.hpp>
+ #include <include/async_resolve.hpp>
+
+@@ -44,6 +45,8 @@ enum class ConnState
+ resolved,
+ connectInProgress,
+ connectFailed,
++ handshakeInProgress,
++ handshakeFailed,
+ connected,
+ sendInProgress,
+ sendFailed,
+@@ -62,7 +65,9 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ {
+ private:
+ crow::async_resolve::Resolver resolver;
++ boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv12_client};
+ boost::beast::tcp_stream conn;
++ std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream&>> sslConn;
+ boost::asio::steady_timer timer;
+ boost::beast::flat_static_buffer<httpReadBodyLimit> buffer;
+ boost::beast::http::request<boost::beast::http::string_body> req;
+@@ -111,23 +116,52 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ void doConnect()
+ {
+ state = ConnState::connectInProgress;
++ sslConn.emplace(conn, ctx);
+
+ BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port;
++ auto respHandler = [self(shared_from_this())](
++ const boost::beast::error_code ec,
++ const boost::asio::ip::tcp::endpoint& endpoint) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Connect " << endpoint
++ << " failed: " << ec.message();
++ self->state = ConnState::connectFailed;
++ self->handleConnState();
++ return;
++ }
+
++ BMCWEB_LOG_DEBUG << "Connected to: " << endpoint;
++ if (self->sslConn)
++ {
++ self->performHandshake();
++ }
++ else
++ {
++ self->handleConnState();
++ }
++ };
+ conn.expires_after(std::chrono::seconds(30));
+- conn.async_connect(
+- endPoints, [self(shared_from_this())](
+- const boost::beast::error_code ec,
+- const boost::asio::ip::tcp::endpoint& endpoint) {
++ conn.async_connect(endPoints, std::move(respHandler));
++ }
++
++ void performHandshake()
++ {
++ state = ConnState::handshakeInProgress;
++
++ sslConn->async_handshake(
++ boost::asio::ssl::stream_base::client,
++ [self(shared_from_this())](const boost::beast::error_code ec) {
+ if (ec)
+ {
+- BMCWEB_LOG_ERROR << "Connect " << endpoint
+- << " failed: " << ec.message();
+- self->state = ConnState::connectFailed;
++ BMCWEB_LOG_ERROR << "SSL handshake failed: "
++ << ec.message();
++ self->state = ConnState::handshakeFailed;
+ self->handleConnState();
+ return;
+ }
+- BMCWEB_LOG_DEBUG << "Connected to: " << endpoint;
++
++ BMCWEB_LOG_DEBUG << "SSL Handshake successfull";
+ self->state = ConnState::connected;
+ self->handleConnState();
+ });
+@@ -135,106 +169,159 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+
+ void sendMessage(const std::string& data)
+ {
+- state = ConnState::sendInProgress;
+-
+ BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port;
++ state = ConnState::sendInProgress;
+
+ req.body() = data;
+ req.prepare_payload();
+
+- // Send the HTTP request to the remote host
+- boost::beast::http::async_write(
+- conn, req,
+- [self(shared_from_this())](const boost::beast::error_code& ec,
+- const std::size_t& bytesTransferred) {
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "sendMessage() failed: "
+- << ec.message();
+- self->state = ConnState::sendFailed;
+- self->handleConnState();
+- return;
+- }
+- BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: "
+- << bytesTransferred;
+- boost::ignore_unused(bytesTransferred);
++ auto respHandler = [self(shared_from_this())](
++ const boost::beast::error_code ec,
++ const std::size_t& bytesTransferred) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "sendMessage() failed: " << ec.message();
++ self->state = ConnState::sendFailed;
++ self->handleConnState();
++ return;
++ }
+
+- self->recvMessage();
+- });
+- }
++ BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: "
++ << bytesTransferred;
++ boost::ignore_unused(bytesTransferred);
++ self->recvMessage();
++ };
+
++ conn.expires_after(std::chrono::seconds(30));
++ if (sslConn)
++ {
++ boost::beast::http::async_write(*sslConn, req,
++ std::move(respHandler));
++ }
++ else
++ {
++ boost::beast::http::async_write(conn, req, std::move(respHandler));
++ }
++ }
+ void recvMessage()
+ {
+ state = ConnState::recvInProgress;
+
++ auto respHandler = [self(shared_from_this())](
++ const boost::beast::error_code ec,
++ const std::size_t& bytesTransferred) {
++ if (ec && ec != boost::asio::ssl::error::stream_truncated)
++ {
++ BMCWEB_LOG_ERROR << "recvMessage() failed: " << ec.message();
++
++ self->state = ConnState::recvFailed;
++ self->handleConnState();
++ return;
++ }
++
++ BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: "
++ << bytesTransferred;
++ boost::ignore_unused(bytesTransferred);
++ // Send is successful, Lets remove data from queue
++ // check for next request data in queue.
++ if (!self->requestDataQueue.empty())
++ {
++ self->requestDataQueue.pop_front();
++ }
++ self->state = ConnState::idle;
++ // Keep the connection alive if server supports it
++ // Else close the connection
++ BMCWEB_LOG_DEBUG << "recvMessage() keepalive : "
++ << self->parser->keep_alive();
++ if (!self->parser->keep_alive())
++ {
++ // Abort the connection since server is not keep-alive enabled
++ self->state = ConnState::abortConnection;
++ }
++
++ // Returns ownership of the parsed message
++ self->parser->release();
++
++ self->handleConnState();
++ };
+ parser.emplace(std::piecewise_construct, std::make_tuple());
+ parser->body_limit(httpReadBodyLimit);
+
+ // Check only for the response header
+ parser->skip(true);
++ conn.expires_after(std::chrono::seconds(30));
++ if (sslConn)
++ {
++ boost::beast::http::async_read(*sslConn, buffer, *parser,
++ std::move(respHandler));
++ }
++ else
++ {
++ boost::beast::http::async_read(conn, buffer, *parser,
++ std::move(respHandler));
++ }
++ }
++ void doClose()
++ {
++ state = ConnState::closeInProgress;
+
+- // Receive the HTTP response
+- boost::beast::http::async_read(
+- conn, buffer, *parser,
+- [self(shared_from_this())](const boost::beast::error_code& ec,
+- const std::size_t& bytesTransferred) {
++ // Set the timeout on the tcp stream socket for the async operation
++ conn.expires_after(std::chrono::seconds(30));
++ if (sslConn)
++ {
++ sslConn->async_shutdown([self = shared_from_this()](
++ const boost::system::error_code ec) {
+ if (ec)
+ {
+- BMCWEB_LOG_ERROR << "recvMessage() failed: "
+- << ec.message();
+- self->state = ConnState::recvFailed;
+- self->handleConnState();
+- return;
++ // Many https server closes connection abruptly
++ // i.e witnout close_notify. More details are at
++ // https://github.com/boostorg/beast/issues/824
++ if (ec == boost::asio::ssl::error::stream_truncated)
++ {
++ BMCWEB_LOG_INFO << "doClose(): Connection "
++ "closed by server. ";
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "doClose() failed: "
++ << ec.message();
++ }
+ }
+- BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: "
+- << bytesTransferred;
+- BMCWEB_LOG_DEBUG << "recvMessage() data: "
+- << self->parser->get();
+-
+- // Send is successful, Lets remove data from queue
+- // check for next request data in queue.
+- if (!self->requestDataQueue.empty())
++ else
+ {
+- self->requestDataQueue.pop_front();
++ BMCWEB_LOG_DEBUG << "Connection closed gracefully...";
+ }
+- self->state = ConnState::idle;
++ self->conn.close();
+
+- // Keep the connection alive if server supports it
+- // Else close the connection
+- BMCWEB_LOG_DEBUG << "recvMessage() keepalive : "
+- << self->parser->keep_alive();
+- if (!self->parser->keep_alive())
++ if ((self->state != ConnState::suspended) &&
++ (self->state != ConnState::terminated))
+ {
+- // Abort the connection since server is not keep-alive
+- // enabled
+- self->state = ConnState::abortConnection;
++ self->state = ConnState::closed;
++ self->handleConnState();
+ }
+-
+- // Returns ownership of the parsed message
+- self->parser->release();
+-
+- self->handleConnState();
+ });
+- }
+-
+- void doClose()
+- {
+- state = ConnState::closeInProgress;
+- boost::beast::error_code ec;
+- conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
+- conn.close();
+-
+- // not_connected happens sometimes so don't bother reporting it.
+- if (ec && ec != boost::beast::errc::not_connected)
+- {
+- BMCWEB_LOG_ERROR << "shutdown failed: " << ec.message();
+- return;
+ }
+- BMCWEB_LOG_DEBUG << "Connection closed gracefully";
+- if ((state != ConnState::suspended) && (state != ConnState::terminated))
++ else
+ {
+- state = ConnState::closed;
+- handleConnState();
++ boost::beast::error_code ec;
++ conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both,
++ ec);
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "doClose() failed: " << ec.message();
++ }
++ else
++ {
++ BMCWEB_LOG_DEBUG << "Connection closed gracefully...";
++ }
++ conn.close();
++
++ if ((state != ConnState::suspended) &&
++ (state != ConnState::terminated))
++ {
++ state = ConnState::closed;
++ handleConnState();
++ }
+ }
+ }
+
+@@ -301,6 +388,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ {
+ case ConnState::resolveInProgress:
+ case ConnState::connectInProgress:
++ case ConnState::handshakeInProgress:
+ case ConnState::sendInProgress:
+ case ConnState::recvInProgress:
+ case ConnState::closeInProgress:
+@@ -332,6 +420,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ }
+ case ConnState::resolveFailed:
+ case ConnState::connectFailed:
++ case ConnState::handshakeFailed:
+ case ConnState::sendFailed:
+ case ConnState::recvFailed:
+ case ConnState::retry:
+@@ -370,7 +459,8 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ public:
+ explicit HttpClient(boost::asio::io_context& ioc, const std::string& id,
+ const std::string& destIP, const std::string& destPort,
+- const std::string& destUri) :
++ const std::string& destUri,
++ const std::string& uriProto) :
+ conn(ioc),
+ timer(ioc), req(boost::beast::http::verb::post, destUri, 11),
+ state(ConnState::initialized), subId(id), host(destIP), port(destPort),
+@@ -383,8 +473,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ req.keep_alive(true);
+
+ requestDataQueue.set_capacity(maxRequestQueueSize);
++ if (uriProto == "https")
++ {
++ sslConn.emplace(conn, ctx);
++ }
+ }
+-
+ void sendData(const std::string& data)
+ {
+ if ((state == ConnState::suspended) || (state == ConnState::terminated))
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index c999121..267c857 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -398,7 +398,7 @@ class Subscription
+ {
+ conn = std::make_shared<crow::HttpClient>(
+ crow::connections::systemBus->get_io_context(), id, host, port,
+- path);
++ path, uriProto);
+ }
+
+ Subscription(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) :
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch
new file mode 100644
index 000000000..cd59ed94d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch
@@ -0,0 +1,478 @@
+From 0c531d959364192697290c1489d5f7b1bdd7a665 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Fri, 12 Mar 2021 18:53:25 +0000
+Subject: [PATCH] Add Server-Sent-Events support
+
+Server-Sent Events is a standard describing how servers can
+initiate data transmission towards clients once an initial
+client connection has been established. Unlike websockets
+(which are bidirectional), Server-Sent Events are
+unidirectional and commonly used to send message updates or
+continuous data streams to a browser client.
+
+This is base patch for adding Server-Sent events support to
+bmcweb. Redfish eventservice SSE style subscription uses
+this and will be loaded on top of this commit.
+
+Tested:
+ - Tested using follow-up patch on top which adds
+ support for Redfish EventService SSE style subscription
+ and observed events are getting sent periodically.
+
+Change-Id: I36956565cbba30c2007852c9471f477f6d1736e9
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+---
+ http/http_connection.hpp | 14 +-
+ http/http_response.hpp | 7 +-
+ http/routing.hpp | 71 ++++++++++
+ http/server_sent_event.hpp | 279 +++++++++++++++++++++++++++++++++++++
+ 4 files changed, 365 insertions(+), 6 deletions(-)
+ create mode 100644 http/server_sent_event.hpp
+
+diff --git a/http/http_connection.hpp b/http/http_connection.hpp
+index 6172b3a..fc9fc60 100644
+--- a/http/http_connection.hpp
++++ b/http/http_connection.hpp
+@@ -326,7 +326,7 @@ class Connection :
+ BMCWEB_LOG_INFO << "Request: "
+ << " " << this << " HTTP/" << req->version() / 10 << "."
+ << req->version() % 10 << ' ' << req->methodString()
+- << " " << req->target() << " " << req->ipAddress;
++ << " " << req->url << " " << req->ipAddress;
+
+ needToCallAfterHandlers = false;
+
+@@ -345,11 +345,15 @@ class Connection :
+ boost::asio::post(self->adaptor.get_executor(),
+ [self] { self->completeRequest(); });
+ };
+- if (req->isUpgrade() &&
+- boost::iequals(
+- req->getHeaderValue(boost::beast::http::field::upgrade),
+- "websocket"))
++
++ if ((req->isUpgrade() &&
++ boost::iequals(req->getHeaderValue(
++ boost::beast::http::field::upgrade),
++ "websocket")) ||
++ (req->url == "/sse"))
+ {
++ BMCWEB_LOG_DEBUG << "Request: " << this
++ << " is getting upgraded";
+ handler->handleUpgrade(*req, res, std::move(adaptor));
+ // delete lambda with self shared_ptr
+ // to enable connection destruction
+diff --git a/http/http_response.hpp b/http/http_response.hpp
+index 7965704..29c56e1 100644
+--- a/http/http_response.hpp
++++ b/http/http_response.hpp
+@@ -13,10 +13,15 @@ namespace crow
+ template <typename Adaptor, typename Handler>
+ class Connection;
+
++template <typename Adaptor>
++class SseConnectionImpl;
++
+ struct Response
+ {
+ template <typename Adaptor, typename Handler>
+ friend class crow::Connection;
++ template <typename Adaptor>
++ friend class crow::SseConnectionImpl;
+ using response_type =
+ boost::beast::http::response<boost::beast::http::string_body>;
+
+@@ -136,8 +141,8 @@ struct Response
+
+ private:
+ bool completed{};
+- std::function<void()> completeRequestHandler;
+ std::function<bool()> isAliveHelper;
++ std::function<void()> completeRequestHandler;
+
+ // In case of a JSON object, set the Content-Type header
+ void jsonMode()
+diff --git a/http/routing.hpp b/http/routing.hpp
+index dd07523..7ddc6b0 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -6,6 +6,7 @@
+ #include "http_response.hpp"
+ #include "logging.hpp"
+ #include "privileges.hpp"
++#include "server_sent_event.hpp"
+ #include "sessions.hpp"
+ #include "utility.hpp"
+ #include "websocket.hpp"
+@@ -398,6 +399,68 @@ class WebSocketRule : public BaseRule
+ std::function<void(crow::websocket::Connection&)> errorHandler;
+ };
+
++class SseSocketRule : public BaseRule
++{
++ using self_t = SseSocketRule;
++
++ public:
++ SseSocketRule(const std::string& ruleIn) : BaseRule(ruleIn)
++ {}
++
++ void validate() override
++ {}
++
++ void handle(const Request&,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const RoutingParams&) override
++ {
++ asyncResp->res.result(boost::beast::http::status::not_found);
++ }
++
++ void handleUpgrade(const Request& req, Response&,
++ boost::asio::ip::tcp::socket&& adaptor) override
++ {
++ std::shared_ptr<crow::SseConnectionImpl<boost::asio::ip::tcp::socket>>
++ myConnection = std::make_shared<
++ crow::SseConnectionImpl<boost::asio::ip::tcp::socket>>(
++ req, std::move(adaptor), openHandler, closeHandler);
++ myConnection->start();
++ }
++#ifdef BMCWEB_ENABLE_SSL
++ void handleUpgrade(const Request& req, Response&,
++ boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
++ adaptor) override
++ {
++ std::shared_ptr<crow::SseConnectionImpl<
++ boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
++ myConnection = std::make_shared<crow::SseConnectionImpl<
++ boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
++ req, std::move(adaptor), openHandler, closeHandler);
++ myConnection->start();
++ }
++#endif
++
++ template <typename Func>
++ self_t& onopen(Func f)
++ {
++ openHandler = f;
++ return *this;
++ }
++
++ template <typename Func>
++ self_t& onclose(Func f)
++ {
++ closeHandler = f;
++ return *this;
++ }
++
++ private:
++ std::function<void(std::shared_ptr<crow::SseConnection>&,
++ const crow::Request&, crow::Response&)>
++ openHandler;
++ std::function<void(std::shared_ptr<crow::SseConnection>&)> closeHandler;
++};
++
+ template <typename T>
+ struct RuleParameterTraits
+ {
+@@ -410,6 +473,14 @@ struct RuleParameterTraits
+ return *p;
+ }
+
++ SseSocketRule& serverSentEvent()
++ {
++ self_t* self = static_cast<self_t*>(this);
++ SseSocketRule* p = new SseSocketRule(self->rule);
++ self->ruleToUpgrade.reset(p);
++ return *p;
++ }
++
+ self_t& name(const std::string_view name) noexcept
+ {
+ self_t* self = static_cast<self_t*>(this);
+diff --git a/http/server_sent_event.hpp b/http/server_sent_event.hpp
+new file mode 100644
+index 0000000..41d18ed
+--- /dev/null
++++ b/http/server_sent_event.hpp
+@@ -0,0 +1,279 @@
++#pragma once
++#include "http_request.hpp"
++
++#include <boost/algorithm/string/predicate.hpp>
++#include <boost/asio/buffer.hpp>
++#include <boost/beast/http/buffer_body.hpp>
++#include <boost/beast/websocket.hpp>
++
++#include <array>
++#include <functional>
++
++#ifdef BMCWEB_ENABLE_SSL
++#include <boost/beast/websocket/ssl.hpp>
++#endif
++
++namespace crow
++{
++
++struct SseConnection : std::enable_shared_from_this<SseConnection>
++{
++ public:
++ SseConnection(const crow::Request& reqIn) : req(reqIn)
++ {}
++ virtual ~SseConnection() = default;
++
++ virtual boost::asio::io_context& getIoContext() = 0;
++ virtual void sendSSEHeader() = 0;
++ virtual void completeRequest() = 0;
++ virtual void close(const std::string_view msg = "quit") = 0;
++ virtual void sendEvent(const std::string_view id,
++ const std::string_view msg) = 0;
++
++ crow::Request req;
++ crow::Response res;
++};
++
++template <typename Adaptor>
++class SseConnectionImpl : public SseConnection
++{
++ public:
++ SseConnectionImpl(
++ const crow::Request& reqIn, Adaptor adaptorIn,
++ std::function<void(std::shared_ptr<SseConnection>&,
++ const crow::Request&, crow::Response&)>
++ openHandler,
++ std::function<void(std::shared_ptr<SseConnection>&)> closeHandler) :
++ SseConnection(reqIn),
++ adaptor(std::move(adaptorIn)), openHandler(std::move(openHandler)),
++ closeHandler(std::move(closeHandler))
++ {
++ BMCWEB_LOG_DEBUG << "SseConnectionImpl: SSE constructor " << this;
++ }
++
++ ~SseConnectionImpl() override
++ {
++ res.completeRequestHandler = nullptr;
++ BMCWEB_LOG_DEBUG << "SseConnectionImpl: SSE destructor " << this;
++ }
++
++ boost::asio::io_context& getIoContext() override
++ {
++ return static_cast<boost::asio::io_context&>(
++ adaptor.get_executor().context());
++ }
++
++ void start()
++ {
++ // Register for completion callback.
++ res.completeRequestHandler = [this, self(shared_from_this())] {
++ boost::asio::post(this->adaptor.get_executor(),
++ [self] { self->completeRequest(); });
++ };
++
++ if (openHandler)
++ {
++ std::shared_ptr<SseConnection> self = this->shared_from_this();
++ openHandler(self, req, res);
++ }
++ }
++
++ void close(const std::string_view msg) override
++ {
++ BMCWEB_LOG_DEBUG << "Closing SSE connection " << this << " - " << msg;
++ boost::beast::get_lowest_layer(adaptor).close();
++
++ // send notification to handler for cleanup
++ if (closeHandler)
++ {
++ std::shared_ptr<SseConnection> self = this->shared_from_this();
++ closeHandler(self);
++ }
++ }
++
++ void sendSSEHeader() override
++ {
++ BMCWEB_LOG_DEBUG << "Starting SSE connection";
++ using BodyType = boost::beast::http::buffer_body;
++ auto response =
++ std::make_shared<boost::beast::http::response<BodyType>>(
++ boost::beast::http::status::ok, 11);
++ auto serializer =
++ std::make_shared<boost::beast::http::response_serializer<BodyType>>(
++ *response);
++
++ response->set(boost::beast::http::field::server, "bmcweb");
++ response->set(boost::beast::http::field::content_type,
++ "text/event-stream");
++ response->body().data = nullptr;
++ response->body().size = 0;
++ response->body().more = true;
++
++ boost::beast::http::async_write_header(
++ adaptor, *serializer,
++ [this, self(shared_from_this()), response, serializer](
++ const boost::beast::error_code& ec, const std::size_t&) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Error sending header" << ec;
++ close("async_write_header failed");
++ return;
++ }
++ BMCWEB_LOG_DEBUG << "SSE header sent - Connection established";
++
++ // SSE stream header sent, So lets setup monitor.
++ // Any read data on this stream will be error in case of SSE.
++ setupRead();
++ });
++ }
++
++ void setupRead()
++ {
++ adaptor.async_read_some(
++ outputBuffer.prepare(outputBuffer.capacity() - outputBuffer.size()),
++ [this](const boost::system::error_code& ec, std::size_t bytesRead) {
++ BMCWEB_LOG_DEBUG << "async_read_some: Read " << bytesRead
++ << " bytes";
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Read error: " << ec;
++ }
++ outputBuffer.commit(bytesRead);
++ outputBuffer.consume(bytesRead);
++
++ // After establishing SSE stream, Reading data on this
++ // stream means client is disobeys the SSE protocol.
++ // Read the data to avoid buffer attacks and close connection.
++ close("Close SSE connection");
++ return;
++ });
++ }
++
++ void doWrite()
++ {
++ if (doingWrite)
++ {
++ return;
++ }
++ if (inputBuffer.size() == 0)
++ {
++ BMCWEB_LOG_DEBUG << "inputBuffer is empty... Bailing out";
++ return;
++ }
++ doingWrite = true;
++
++ adaptor.async_write_some(
++ inputBuffer.data(), [this, self(shared_from_this())](
++ boost::beast::error_code ec,
++ const std::size_t& bytesTransferred) {
++ doingWrite = false;
++ inputBuffer.consume(bytesTransferred);
++
++ if (ec == boost::asio::error::eof)
++ {
++ BMCWEB_LOG_ERROR << "async_write_some() SSE stream closed";
++ close("SSE stream closed");
++ return;
++ }
++
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "async_write_some() failed: "
++ << ec.message();
++ close("async_write_some failed");
++ return;
++ }
++ BMCWEB_LOG_DEBUG << "async_write_some() bytes transferred: "
++ << bytesTransferred;
++
++ doWrite();
++ });
++ }
++
++ void completeRequest() override
++ {
++ BMCWEB_LOG_DEBUG << "SSE completeRequest() handler";
++ if (res.body().empty() && !res.jsonValue.empty())
++ {
++ res.addHeader("Content-Type", "application/json");
++ res.body() = res.jsonValue.dump(
++ 2, ' ', true, nlohmann::json::error_handler_t::replace);
++ }
++
++ res.preparePayload();
++ auto serializer =
++ std::make_shared<boost::beast::http::response_serializer<
++ boost::beast::http::string_body>>(*res.stringResponse);
++
++ boost::beast::http::async_write(
++ adaptor, *serializer,
++ [this, self(shared_from_this()),
++ serializer](const boost::system::error_code& ec,
++ std::size_t bytesTransferred) {
++ BMCWEB_LOG_DEBUG << this << " async_write " << bytesTransferred
++ << " bytes";
++ if (ec)
++ {
++ BMCWEB_LOG_DEBUG << this << " from async_write failed";
++ return;
++ }
++ res.clear();
++
++ BMCWEB_LOG_DEBUG << this
++ << " Closing SSE connection - Request invalid";
++ close("Request invalid");
++ });
++
++ // delete lambda with self shared_ptr
++ // to enable connection destruction
++ res.completeRequestHandler = nullptr;
++ }
++
++ void sendEvent(const std::string_view id,
++ const std::string_view msg) override
++ {
++ if (msg.empty())
++ {
++ BMCWEB_LOG_DEBUG << "Empty data, bailing out.";
++ return;
++ }
++
++ std::string rawData;
++ if (!id.empty())
++ {
++ rawData += "id: ";
++ rawData.append(id.begin(), id.end());
++ rawData += "\n";
++ }
++
++ rawData += "data: ";
++ for (char character : msg)
++ {
++ rawData += character;
++ if (character == '\n')
++ {
++ rawData += "data: ";
++ }
++ }
++ rawData += "\n\n";
++
++ boost::asio::buffer_copy(inputBuffer.prepare(rawData.size()),
++ boost::asio::buffer(rawData));
++ inputBuffer.commit(rawData.size());
++
++ doWrite();
++ }
++
++ private:
++ Adaptor adaptor;
++
++ boost::beast::flat_static_buffer<1024U * 8U> outputBuffer;
++ boost::beast::flat_static_buffer<1024U * 64U> inputBuffer;
++ bool doingWrite = false;
++
++ std::function<void(std::shared_ptr<SseConnection>&, const crow::Request&,
++ crow::Response&)>
++ openHandler;
++ std::function<void(std::shared_ptr<SseConnection>&)> closeHandler;
++};
++} // namespace crow
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch
new file mode 100644
index 000000000..37609c154
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch
@@ -0,0 +1,666 @@
+From bcb80fc9a86555c74b56b5b37615601d3fbfae31 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Tue, 16 Mar 2021 15:37:24 +0000
+Subject: [PATCH] Add SSE style subscription support to eventservice
+
+This commit adds the SSE style eventservice subscription
+style event. Using this, end user can subscribe for
+Redfish event logs using GET on SSE usri from
+browser.
+URI: /redfish/v1/EventService/Subscriptions/SSE
+
+Tested:
+ - From Browser did GET on above SSE URI and
+ generated some Redfish event logs(power cycle)
+ and saw redfish event logs streaming on browser.
+ - After SSE registration, Check Subscription collections
+ and GET on individual subscription and saw desired
+ response.
+ - Ran RedfishValidation and its passed.
+
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Change-Id: I7f4b7a34974080739c4ba968ed570489af0474de
+---
+ http/http_connection.hpp | 2 +-
+ include/eventservice_sse.hpp | 75 +++++
+ .../include/event_service_manager.hpp | 109 +++++--
+ redfish-core/include/server_sent_events.hpp | 291 ------------------
+ redfish-core/lib/event_service.hpp | 4 +-
+ src/webserver_main.cpp | 2 +
+ 6 files changed, 163 insertions(+), 320 deletions(-)
+ create mode 100644 include/eventservice_sse.hpp
+ delete mode 100644 redfish-core/include/server_sent_events.hpp
+
+diff --git a/http/http_connection.hpp b/http/http_connection.hpp
+index fc9fc60..3afb4da 100644
+--- a/http/http_connection.hpp
++++ b/http/http_connection.hpp
+@@ -350,7 +350,7 @@ class Connection :
+ boost::iequals(req->getHeaderValue(
+ boost::beast::http::field::upgrade),
+ "websocket")) ||
+- (req->url == "/sse"))
++ (req->url == "/redfish/v1/EventService/Subscriptions/SSE"))
+ {
+ BMCWEB_LOG_DEBUG << "Request: " << this
+ << " is getting upgraded";
+diff --git a/include/eventservice_sse.hpp b/include/eventservice_sse.hpp
+new file mode 100644
+index 0000000..6c98e6e
+--- /dev/null
++++ b/include/eventservice_sse.hpp
+@@ -0,0 +1,75 @@
++#pragma once
++
++#include <app.hpp>
++#include <event_service_manager.hpp>
++
++namespace redfish
++{
++namespace eventservice_sse
++{
++
++static bool createSubscription(std::shared_ptr<crow::SseConnection>& conn,
++ const crow::Request& req, crow::Response& res)
++{
++ if ((EventServiceManager::getInstance().getNumberOfSubscriptions() >=
++ maxNoOfSubscriptions) ||
++ EventServiceManager::getInstance().getNumberOfSSESubscriptions() >=
++ maxNoOfSSESubscriptions)
++ {
++ BMCWEB_LOG_ERROR << "Max SSE subscriptions reached";
++ messages::eventSubscriptionLimitExceeded(res);
++ res.end();
++ return false;
++ }
++ BMCWEB_LOG_DEBUG << "Request query param size: " << req.urlParams.size();
++
++ std::shared_ptr<redfish::Subscription> subValue =
++ std::make_shared<redfish::Subscription>(std::move(conn));
++
++ // GET on this URI means, Its SSE subscriptionType.
++ subValue->subscriptionType = redfish::subscriptionTypeSSE;
++
++ // TODO: parse $filter query params and fill config.
++ subValue->protocol = "Redfish";
++ subValue->retryPolicy = "TerminateAfterRetries";
++ subValue->eventFormatType = "Event";
++
++ std::string id =
++ redfish::EventServiceManager::getInstance().addSubscription(subValue,
++ false);
++ if (id.empty())
++ {
++ messages::internalError(res);
++ res.end();
++ return false;
++ }
++
++ return true;
++}
++
++static void deleteSubscription(std::shared_ptr<crow::SseConnection>& conn)
++{
++ redfish::EventServiceManager::getInstance().deleteSubscription(conn);
++}
++
++inline void requestRoutes(App& app)
++{
++ BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/SSE")
++ .privileges({"ConfigureComponents", "ConfigureManager"})
++ .serverSentEvent()
++ .onopen([](std::shared_ptr<crow::SseConnection>& conn,
++ const crow::Request& req, crow::Response& res) {
++ BMCWEB_LOG_DEBUG << "Connection " << conn << " opened.";
++ if (createSubscription(conn, req, res))
++ {
++ // All success, lets send SSE haader
++ conn->sendSSEHeader();
++ }
++ })
++ .onclose([](std::shared_ptr<crow::SseConnection>& conn) {
++ BMCWEB_LOG_DEBUG << "Connection " << conn << " closed";
++ deleteSubscription(conn);
++ });
++}
++} // namespace eventservice_sse
++} // namespace redfish
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index fa4e41a..ac644c1 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -23,13 +23,15 @@
+ #include <sys/inotify.h>
+
+ #include <boost/asio/io_context.hpp>
++#include <boost/beast/core/span.hpp>
+ #include <boost/container/flat_map.hpp>
+ #include <error_messages.hpp>
+ #include <http_client.hpp>
+ #include <random.hpp>
+-#include <server_sent_events.hpp>
++#include <server_sent_event.hpp>
+ #include <utils/json_utils.hpp>
+
++#include <algorithm>
+ #include <cstdlib>
+ #include <ctime>
+ #include <fstream>
+@@ -46,9 +48,27 @@ using EventServiceConfig = std::tuple<bool, uint32_t, uint32_t>;
+ static constexpr const char* eventFormatType = "Event";
+ static constexpr const char* metricReportFormatType = "MetricReport";
+
++static constexpr const char* subscriptionTypeSSE = "SSE";
+ static constexpr const char* eventServiceFile =
+ "/var/lib/bmcweb/eventservice_config.json";
+
++static constexpr const uint8_t maxNoOfSubscriptions = 20;
++static constexpr const uint8_t maxNoOfSSESubscriptions = 10;
++
++#ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
++static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
++static constexpr const char* redfishEventLogDir = "/var/log";
++static constexpr const char* redfishEventLogFile = "/var/log/redfish";
++static constexpr const size_t iEventSize = sizeof(inotify_event);
++static int inotifyFd = -1;
++static int dirWatchDesc = -1;
++static int fileWatchDesc = -1;
++
++// <ID, timestamp, RedfishLogId, registryPrefix, MessageId, MessageArgs>
++using EventLogObjectsType =
++ std::tuple<std::string, std::string, std::string, std::string, std::string,
++ std::vector<std::string>>;
++
+ namespace message_registries
+ {
+ inline boost::beast::span<const MessageEntry>
+@@ -68,24 +88,6 @@ inline boost::beast::span<const MessageEntry>
+ }
+ return boost::beast::span<const MessageEntry>(openbmc::registry);
+ }
+-} // namespace message_registries
+-
+-#ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
+-static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
+-static constexpr const char* redfishEventLogDir = "/var/log";
+-static constexpr const char* redfishEventLogFile = "/var/log/redfish";
+-static constexpr const size_t iEventSize = sizeof(inotify_event);
+-static int inotifyFd = -1;
+-static int dirWatchDesc = -1;
+-static int fileWatchDesc = -1;
+-
+-// <ID, timestamp, RedfishLogId, registryPrefix, MessageId, MessageArgs>
+-using EventLogObjectsType =
+- std::tuple<std::string, std::string, std::string, std::string, std::string,
+- std::vector<std::string>>;
+-
+-namespace message_registries
+-{
+ static const Message*
+ getMsgFromRegistry(const std::string& messageKey,
+ const boost::beast::span<const MessageEntry>& registry)
+@@ -401,11 +403,9 @@ class Subscription
+ path);
+ }
+
+- Subscription(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) :
+- eventSeqNum(1)
+- {
+- sseConn = std::make_shared<crow::ServerSentEvents>(adaptor);
+- }
++ Subscription(const std::shared_ptr<crow::SseConnection>& adaptor) :
++ sseConn(adaptor), eventSeqNum(1)
++ {}
+
+ ~Subscription() = default;
+
+@@ -430,7 +430,7 @@ class Subscription
+
+ if (sseConn != nullptr)
+ {
+- sseConn->sendData(eventSeqNum, msg);
++ sseConn->sendEvent(std::to_string(eventSeqNum), msg);
+ }
+ }
+
+@@ -520,6 +520,7 @@ class Subscription
+
+ this->sendEvent(
+ msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace));
++ this->eventSeqNum++;
+ }
+ #endif
+
+@@ -590,14 +591,39 @@ class Subscription
+ return eventSeqNum;
+ }
+
++ void setSubscriptionId(const std::string& id)
++ {
++ BMCWEB_LOG_DEBUG << "Subscription ID: " << id;
++ subId = id;
++ }
++
++ std::string getSubscriptionId()
++ {
++ return subId;
++ }
++
++ std::optional<std::string>
++ getSubscriptionId(const std::shared_ptr<crow::SseConnection>& connPtr)
++ {
++ if (sseConn != nullptr && connPtr == sseConn)
++ {
++ BMCWEB_LOG_DEBUG << __FUNCTION__
++ << " conn matched, subId: " << subId;
++ return subId;
++ }
++
++ return std::nullopt;
++ }
++
+ private:
++ std::shared_ptr<crow::SseConnection> sseConn = nullptr;
+ uint64_t eventSeqNum;
+ std::string host;
+ std::string port;
+ std::string path;
+ std::string uriProto;
+ std::shared_ptr<crow::HttpClient> conn = nullptr;
+- std::shared_ptr<crow::ServerSentEvents> sseConn = nullptr;
++ std::string subId;
+ };
+
+ static constexpr const bool defaultEnabledState = true;
+@@ -988,6 +1014,8 @@ class EventServiceManager
+ subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
+ subValue->updateRetryPolicy();
+
++ // Set Subscription ID for back trace
++ subValue->setSubscriptionId(id);
+ return id;
+ }
+
+@@ -1012,11 +1040,40 @@ class EventServiceManager
+ }
+ }
+
++ void deleteSubscription(const std::shared_ptr<crow::SseConnection>& connPtr)
++ {
++ for (const auto& it : this->subscriptionsMap)
++ {
++ std::shared_ptr<Subscription> entry = it.second;
++ if (entry->subscriptionType == subscriptionTypeSSE)
++ {
++ std::optional<std::string> id =
++ entry->getSubscriptionId(connPtr);
++ if (id)
++ {
++ deleteSubscription(*id);
++ return;
++ }
++ }
++ }
++ }
++
+ size_t getNumberOfSubscriptions()
+ {
+ return subscriptionsMap.size();
+ }
+
++ size_t getNumberOfSSESubscriptions() const
++ {
++ auto count = std::count_if(
++ subscriptionsMap.begin(), subscriptionsMap.end(),
++ [this](const std::pair<std::string, std::shared_ptr<Subscription>>&
++ entry) {
++ return (entry.second->subscriptionType == subscriptionTypeSSE);
++ });
++ return static_cast<size_t>(count);
++ }
++
+ std::vector<std::string> getAllIDs()
+ {
+ std::vector<std::string> idList;
+diff --git a/redfish-core/include/server_sent_events.hpp b/redfish-core/include/server_sent_events.hpp
+deleted file mode 100644
+index 578fa19..0000000
+--- a/redfish-core/include/server_sent_events.hpp
++++ /dev/null
+@@ -1,291 +0,0 @@
+-
+-/*
+-// Copyright (c) 2020 Intel Corporation
+-//
+-// Licensed under the Apache License, Version 2.0 (the "License");
+-// you may not use this file except in compliance with the License.
+-// You may obtain a copy of the License at
+-//
+-// http://www.apache.org/licenses/LICENSE-2.0
+-//
+-// Unless required by applicable law or agreed to in writing, software
+-// distributed under the License is distributed on an "AS IS" BASIS,
+-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-// See the License for the specific language governing permissions and
+-// limitations under the License.
+-*/
+-#pragma once
+-#include "node.hpp"
+-
+-#include <boost/asio/strand.hpp>
+-#include <boost/beast/core/span.hpp>
+-#include <boost/beast/http/buffer_body.hpp>
+-#include <boost/beast/http/message.hpp>
+-#include <boost/beast/version.hpp>
+-
+-#include <cstdlib>
+-#include <functional>
+-#include <iostream>
+-#include <memory>
+-#include <queue>
+-#include <string>
+-
+-namespace crow
+-{
+-
+-static constexpr uint8_t maxReqQueueSize = 50;
+-
+-enum class SseConnState
+-{
+- startInit,
+- initInProgress,
+- initialized,
+- initFailed,
+- sendInProgress,
+- sendFailed,
+- idle,
+- suspended,
+- closed
+-};
+-
+-class ServerSentEvents : public std::enable_shared_from_this<ServerSentEvents>
+-{
+- private:
+- std::shared_ptr<boost::beast::tcp_stream> sseConn;
+- std::queue<std::pair<uint64_t, std::string>> requestDataQueue;
+- std::string outBuffer;
+- SseConnState state;
+- int retryCount;
+- int maxRetryAttempts;
+-
+- void sendEvent(const std::string& id, const std::string& msg)
+- {
+- if (msg.empty())
+- {
+- BMCWEB_LOG_DEBUG << "Empty data, bailing out.";
+- return;
+- }
+-
+- if (state == SseConnState::sendInProgress)
+- {
+- return;
+- }
+- state = SseConnState::sendInProgress;
+-
+- if (!id.empty())
+- {
+- outBuffer += "id: ";
+- outBuffer.append(id.begin(), id.end());
+- outBuffer += "\n";
+- }
+-
+- outBuffer += "data: ";
+- for (char character : msg)
+- {
+- outBuffer += character;
+- if (character == '\n')
+- {
+- outBuffer += "data: ";
+- }
+- }
+- outBuffer += "\n\n";
+-
+- doWrite();
+- }
+-
+- void doWrite()
+- {
+- if (outBuffer.empty())
+- {
+- BMCWEB_LOG_DEBUG << "All data sent successfully.";
+- // Send is successful, Lets remove data from queue
+- // check for next request data in queue.
+- requestDataQueue.pop();
+- state = SseConnState::idle;
+- checkQueue();
+- return;
+- }
+-
+- sseConn->async_write_some(
+- boost::asio::buffer(outBuffer.data(), outBuffer.size()),
+- [self(shared_from_this())](
+- boost::beast::error_code ec,
+- [[maybe_unused]] const std::size_t& bytesTransferred) {
+- self->outBuffer.erase(0, bytesTransferred);
+-
+- if (ec == boost::asio::error::eof)
+- {
+- // Send is successful, Lets remove data from queue
+- // check for next request data in queue.
+- self->requestDataQueue.pop();
+- self->state = SseConnState::idle;
+- self->checkQueue();
+- return;
+- }
+-
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "async_write_some() failed: "
+- << ec.message();
+- self->state = SseConnState::sendFailed;
+- self->checkQueue();
+- return;
+- }
+- BMCWEB_LOG_DEBUG << "async_write_some() bytes transferred: "
+- << bytesTransferred;
+-
+- self->doWrite();
+- });
+- }
+-
+- void startSSE()
+- {
+- if (state == SseConnState::initInProgress)
+- {
+- return;
+- }
+- state = SseConnState::initInProgress;
+-
+- BMCWEB_LOG_DEBUG << "starting SSE connection ";
+- using BodyType = boost::beast::http::buffer_body;
+- auto response =
+- std::make_shared<boost::beast::http::response<BodyType>>(
+- boost::beast::http::status::ok, 11);
+- auto serializer =
+- std::make_shared<boost::beast::http::response_serializer<BodyType>>(
+- *response);
+-
+- // TODO: Add hostname in http header.
+- response->set(boost::beast::http::field::server, "iBMC");
+- response->set(boost::beast::http::field::content_type,
+- "text/event-stream");
+- response->body().data = nullptr;
+- response->body().size = 0;
+- response->body().more = true;
+-
+- boost::beast::http::async_write_header(
+- *sseConn, *serializer,
+- [this, response,
+- serializer](const boost::beast::error_code& ec,
+- [[maybe_unused]] const std::size_t& bytesTransferred) {
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "Error sending header" << ec;
+- state = SseConnState::initFailed;
+- checkQueue();
+- return;
+- }
+-
+- BMCWEB_LOG_DEBUG << "startSSE Header sent.";
+- state = SseConnState::initialized;
+- checkQueue();
+- });
+- }
+-
+- void checkQueue(const bool newRecord = false)
+- {
+- if (requestDataQueue.empty())
+- {
+- BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n";
+- return;
+- }
+-
+- if (retryCount >= maxRetryAttempts)
+- {
+- BMCWEB_LOG_ERROR << "Maximum number of retries is reached.";
+-
+- // Clear queue.
+- while (!requestDataQueue.empty())
+- {
+- requestDataQueue.pop();
+- }
+-
+- // TODO: Take 'DeliveryRetryPolicy' action.
+- // For now, doing 'SuspendRetries' action.
+- state = SseConnState::suspended;
+- return;
+- }
+-
+- if ((state == SseConnState::initFailed) ||
+- (state == SseConnState::sendFailed))
+- {
+- if (newRecord)
+- {
+- // We are already running async wait and retry.
+- // Since record is added to queue, it gets the
+- // turn in FIFO.
+- return;
+- }
+-
+- retryCount++;
+- // TODO: Perform async wait for retryTimeoutInterval before proceed.
+- }
+- else
+- {
+- // reset retry count.
+- retryCount = 0;
+- }
+-
+- switch (state)
+- {
+- case SseConnState::initInProgress:
+- case SseConnState::sendInProgress:
+- case SseConnState::suspended:
+- case SseConnState::startInit:
+- case SseConnState::closed:
+- // do nothing
+- break;
+- case SseConnState::initFailed:
+- {
+- startSSE();
+- break;
+- }
+- case SseConnState::initialized:
+- case SseConnState::idle:
+- case SseConnState::sendFailed:
+- {
+- std::pair<uint64_t, std::string> reqData =
+- requestDataQueue.front();
+- sendEvent(std::to_string(reqData.first), reqData.second);
+- break;
+- }
+- }
+-
+- return;
+- }
+-
+- public:
+- ServerSentEvents(const ServerSentEvents&) = delete;
+- ServerSentEvents& operator=(const ServerSentEvents&) = delete;
+- ServerSentEvents(ServerSentEvents&&) = delete;
+- ServerSentEvents& operator=(ServerSentEvents&&) = delete;
+-
+- ServerSentEvents(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) :
+- sseConn(adaptor), state(SseConnState::startInit), retryCount(0),
+- maxRetryAttempts(5)
+- {
+- startSSE();
+- }
+-
+- ~ServerSentEvents() = default;
+-
+- void sendData(const uint64_t& id, const std::string& data)
+- {
+- if (state == SseConnState::suspended)
+- {
+- return;
+- }
+-
+- if (requestDataQueue.size() <= maxReqQueueSize)
+- {
+- requestDataQueue.push(std::pair(id, data));
+- checkQueue(true);
+- }
+- else
+- {
+- BMCWEB_LOG_ERROR << "Request queue is full. So ignoring data.";
+- }
+- }
+-};
+-
+-} // namespace crow
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index 64a2009..7c9bb7a 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -34,8 +34,6 @@ static constexpr const std::array<const char*, 1> supportedResourceTypes = {
+ "Task"};
+ #endif
+
+-static constexpr const uint8_t maxNoOfSubscriptions = 20;
+-
+ class EventService : public Node
+ {
+ public:
+@@ -59,6 +57,8 @@ class EventService : public Node
+ {"@odata.type", "#EventService.v1_5_0.EventService"},
+ {"Id", "EventService"},
+ {"Name", "Event Service"},
++ {"ServerSentEventUri",
++ "/redfish/v1/EventService/Subscriptions/SSE"},
+ {"Subscriptions",
+ {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
+ {"Actions",
+diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp
+index 902c32b..d4bd48c 100644
+--- a/src/webserver_main.cpp
++++ b/src/webserver_main.cpp
+@@ -5,6 +5,7 @@
+ #include <cors_preflight.hpp>
+ #include <dbus_monitor.hpp>
+ #include <dbus_singleton.hpp>
++#include <eventservice_sse.hpp>
+ #include <hostname_monitor.hpp>
+ #include <ibm/management_console_rest.hpp>
+ #include <image_upload.hpp>
+@@ -81,6 +82,7 @@ int main(int /*argc*/, char** /*argv*/)
+ #endif
+
+ #ifdef BMCWEB_ENABLE_REDFISH
++ redfish::eventservice_sse::requestRoutes(app);
+ redfish::requestRoutes(app);
+ redfish::RedfishService redfish(app);
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch
new file mode 100644
index 000000000..c3e3acbca
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch
@@ -0,0 +1,292 @@
+From 3dc6f6d807060cf3b38486e4190fd1ba9c66c66b Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Wed, 17 Mar 2021 01:16:50 +0000
+Subject: [PATCH] Add EventService SSE filter support
+
+This commit implements the Event Service SSE stream
+filters support. As per redfish specification:
+The SSE streams have these formats:
+ - Metric report SSE stream
+ - Event message SSE stream
+
+To reduce the amount of data, service supports $filter
+query parameter in SSE URI.
+Below properties support as filter criteria:
+ - EventFormatType( Event & MetricReport)
+ - MessageId
+ - RegistryPrefix
+ - MetricReportDefinition
+
+For more details, refer Redfish specification section 13.5.2
+
+Tested:
+ Created SSE stream with different filters and observed
+ desired events on SSE stream client(browser), some examples
+ - To get all Redfish events,
+ URI: /redfish/v1/EventService/Subscriptions/SSE?$filter=(EventFormatType%20eq%20Event)
+ - To get Redfish events with RegistryPrefix "OpenBMC"
+ URI: /redfish/v1/EventService/Subscriptions/SSE?$filter=(RegistryPrefix%20eq%20OpenBMC)
+ - To get only DC power of Events,
+ URI: /redfish/v1/EventService/Subscriptions/SSE?$filter=(EventFormatType%20eq%20Event)%20and%20(MessageId%20eq%20DCPowerOff)
+
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Change-Id: I55c6f53bb5e57aa1f2d1601f1a16525a33b13bd2
+---
+ include/eventservice_sse.hpp | 141 +++++++++++++++++-
+ redfish-core/include/error_messages.hpp | 9 ++
+ .../include/event_service_manager.hpp | 5 +
+ redfish-core/lib/event_service.hpp | 5 -
+ redfish-core/src/error_messages.cpp | 26 ++++
+ 5 files changed, 177 insertions(+), 9 deletions(-)
+
+diff --git a/include/eventservice_sse.hpp b/include/eventservice_sse.hpp
+index 6c98e6e..01e4126 100644
+--- a/include/eventservice_sse.hpp
++++ b/include/eventservice_sse.hpp
+@@ -23,16 +23,149 @@ static bool createSubscription(std::shared_ptr<crow::SseConnection>& conn,
+ }
+ BMCWEB_LOG_DEBUG << "Request query param size: " << req.urlParams.size();
+
++ // EventService SSE supports only "$filter" query param.
++ if (req.urlParams.size() > 1)
++ {
++ messages::invalidQueryFilter(res);
++ res.end();
++ return false;
++ }
++ std::string eventFormatType;
++ std::string queryFilters;
++ if (req.urlParams.size())
++ {
++ boost::urls::url_view::params_type::iterator it =
++ req.urlParams.find("$filter");
++ if (it == req.urlParams.end())
++ {
++ messages::invalidQueryFilter(res);
++ res.end();
++ return false;
++ }
++ queryFilters = it->value();
++ }
++ else
++ {
++ eventFormatType = "Event";
++ }
++
++ std::vector<std::string> msgIds;
++ std::vector<std::string> regPrefixes;
++ std::vector<std::string> mrdsArray;
++ if (!queryFilters.empty())
++ {
++ // Reading from query params.
++ bool status = readSSEQueryParams(queryFilters, eventFormatType, msgIds,
++ regPrefixes, mrdsArray);
++ if (!status)
++ {
++ messages::invalidObject(res, queryFilters);
++ res.end();
++ return false;
++ }
++
++ // RegsitryPrefix and messageIds are mutuly exclusive as per redfish
++ // specification.
++ if (regPrefixes.size() && msgIds.size())
++ {
++ messages::mutualExclusiveProperties(res, "RegistryPrefix",
++ "MessageId");
++ res.end();
++ return false;
++ }
++
++ if (!eventFormatType.empty())
++ {
++ if (std::find(supportedEvtFormatTypes.begin(),
++ supportedEvtFormatTypes.end(),
++ eventFormatType) == supportedEvtFormatTypes.end())
++ {
++ messages::propertyValueNotInList(res, eventFormatType,
++ "EventFormatType");
++ res.end();
++ return false;
++ }
++ }
++ else
++ {
++ // If nothing specified, using default "Event"
++ eventFormatType = "Event";
++ }
++
++ if (!regPrefixes.empty())
++ {
++ for (const std::string& it : regPrefixes)
++ {
++ if (std::find(supportedRegPrefixes.begin(),
++ supportedRegPrefixes.end(),
++ it) == supportedRegPrefixes.end())
++ {
++ messages::propertyValueNotInList(res, it, "RegistryPrefix");
++ res.end();
++ return false;
++ }
++ }
++ }
++
++ if (!msgIds.empty())
++ {
++ std::vector<std::string> registryPrefix;
++
++ // If no registry prefixes are mentioned, consider all supported
++ // prefixes to validate message ID
++ if (regPrefixes.empty())
++ {
++ registryPrefix.assign(supportedRegPrefixes.begin(),
++ supportedRegPrefixes.end());
++ }
++
++ for (const std::string& id : msgIds)
++ {
++ bool validId = false;
++
++ // Check for Message ID in each of the selected Registry
++ for (const std::string& it : registryPrefix)
++ {
++ const boost::beast::span<
++ const redfish::message_registries::MessageEntry>
++ registry =
++ redfish::message_registries::getRegistryFromPrefix(
++ it);
++
++ if (std::any_of(
++ registry.cbegin(), registry.cend(),
++ [&id](
++ const redfish::message_registries::MessageEntry&
++ messageEntry) {
++ return !id.compare(messageEntry.first);
++ }))
++ {
++ validId = true;
++ break;
++ }
++ }
++
++ if (!validId)
++ {
++ messages::propertyValueNotInList(res, id, "MessageId");
++ res.end();
++ return false;
++ }
++ }
++ }
++ }
++
+ std::shared_ptr<redfish::Subscription> subValue =
+ std::make_shared<redfish::Subscription>(std::move(conn));
+
+ // GET on this URI means, Its SSE subscriptionType.
+- subValue->subscriptionType = redfish::subscriptionTypeSSE;
+-
+- // TODO: parse $filter query params and fill config.
++ subValue->subscriptionType = subscriptionTypeSSE;
+ subValue->protocol = "Redfish";
+ subValue->retryPolicy = "TerminateAfterRetries";
+- subValue->eventFormatType = "Event";
++ subValue->eventFormatType = eventFormatType;
++ subValue->registryMsgIds = msgIds;
++ subValue->registryPrefixes = regPrefixes;
++ subValue->metricReportDefinitions = mrdsArray;
+
+ std::string id =
+ redfish::EventServiceManager::getInstance().addSubscription(subValue,
+diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp
+index 7dfdc80..922dae9 100644
+--- a/redfish-core/include/error_messages.hpp
++++ b/redfish-core/include/error_messages.hpp
+@@ -959,6 +959,15 @@ nlohmann::json mutualExclusiveProperties(const std::string& arg1,
+ void mutualExclusiveProperties(crow::Response& res, const std::string& arg1,
+ const std::string& arg2);
+
++/**
++ * @brief Formats InvalidQueryFilter message into JSON
++ * Message body: "The requested URL contains the invalid query filters"
++ *
++ * @returns Message InvalidQueryFilter formatted to JSON */
++nlohmann::json invalidQueryFilter();
++
++void invalidQueryFilter(crow::Response& res);
++
+ } // namespace messages
+
+ } // namespace redfish
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index e826207..f201134 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -55,6 +55,11 @@ static constexpr const char* eventServiceFile =
+ static constexpr const uint8_t maxNoOfSubscriptions = 20;
+ static constexpr const uint8_t maxNoOfSSESubscriptions = 10;
+
++static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
++ eventFormatType, metricReportFormatType};
++static constexpr const std::array<const char*, 2> supportedRegPrefixes = {
++ "OpenBMC", "TaskEvent"};
++
+ #ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
+ static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
+ static constexpr const char* redfishEventLogDir = "/var/log";
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index 7c9bb7a..297a4ea 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -18,11 +18,6 @@
+
+ namespace redfish
+ {
+-
+-static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
+- eventFormatType, metricReportFormatType};
+-static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
+- "Base", "OpenBMC", "TaskEvent"};
+ static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
+ "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
+
+diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp
+index ad5f819..409adb1 100644
+--- a/redfish-core/src/error_messages.cpp
++++ b/redfish-core/src/error_messages.cpp
+@@ -2147,6 +2147,32 @@ void mutualExclusiveProperties(crow::Response& res, const std::string& arg1,
+ addMessageToErrorJson(res.jsonValue, mutualExclusiveProperties(arg1, arg2));
+ }
+
++/**
++ * @internal
++ * @brief Formats InvalidQueryFilter into JSON
++ *
++ * See header file for more information
++ * @endinternal
++ */
++nlohmann::json invalidQueryFilter()
++{
++ return nlohmann::json{
++ {"@odata.type", "#Message.v1_0_0.Message"},
++ {"MessageId", "Base.1.5.0.InvalidQueryFilter"},
++ {"Message", "The requested url contains the invalid query filter."},
++ {"MessageArgs", nlohmann::json::array()},
++ {"Severity", "Warning"},
++ {"Resolution",
++ "Ensure the correct query filter is specified in requested url "
++ "and resubmit the request."}};
++}
++
++void invalidQueryFilter(crow::Response& res)
++{
++ res.result(boost::beast::http::status::bad_request);
++ addMessageToErrorJson(res.jsonValue, invalidQueryFilter());
++}
++
+ } // namespace messages
+
+ } // namespace redfish
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0007-EventService-Log-events-for-subscription-actions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0007-EventService-Log-events-for-subscription-actions.patch
new file mode 100644
index 000000000..0b12671e5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0007-EventService-Log-events-for-subscription-actions.patch
@@ -0,0 +1,132 @@
+From 0a1390428fd6f5651669f4306f6105d33a24453c Mon Sep 17 00:00:00 2001
+From: Ayushi Smriti <smriti.ayushi@intel.com>
+Date: Mon, 10 May 2021 13:03:37 +0530
+Subject: [PATCH] EventService: Log events for subscription actions
+
+Log redfish event for below 3 actions
+ - Add new subscription
+ - Update existing subscription properties
+ - Delete existing subscription
+in order to notify the subscribed clients on the subscription related
+information.
+
+Modified method name accordingly to indicate the clear purpose and
+added updateSubscription method with subscription id param
+to log event for subscription update.
+
+Tested:
+ - Performed all the above actions and verified the redfish event
+ messages are logged.
+
+Change-Id: I528293e55b1f3401bc2bb09c11c63ae985fbfedb
+Signed-off-by: AppaRao Puli <apparao.puli@intel.com>
+Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com>
+---
+ .../include/event_service_manager.hpp | 35 ++++++++++++++++---
+ redfish-core/lib/event_service.hpp | 2 +-
+ 2 files changed, 32 insertions(+), 5 deletions(-)
+
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 9952ef1..2b957ea 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -22,6 +22,7 @@
+ #include "registries/task_event_message_registry.hpp"
+
+ #include <sys/inotify.h>
++#include <systemd/sd-journal.h>
+
+ #include <boost/asio/io_context.hpp>
+ #include <boost/beast/core/span.hpp>
+@@ -800,7 +801,7 @@ class EventServiceManager
+ return;
+ }
+
+- void updateSubscriptionData()
++ void persistSubscriptionData()
+ {
+ // Persist the config and subscription data.
+ nlohmann::json jsonData;
+@@ -897,7 +898,7 @@ class EventServiceManager
+
+ if (updateConfig)
+ {
+- updateSubscriptionData();
++ persistSubscriptionData();
+ }
+
+ if (updateRetryCfg)
+@@ -992,7 +993,7 @@ class EventServiceManager
+
+ if (updateFile)
+ {
+- updateSubscriptionData();
++ persistSubscriptionData();
+ }
+
+ #ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
+@@ -1007,6 +1008,13 @@ class EventServiceManager
+
+ // Set Subscription ID for back trace
+ subValue->setSubscriptionId(id);
++
++ /* Log event for subscription addition */
++ sd_journal_send("MESSAGE=Event subscription added(Id: %s)", id.c_str(),
++ "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.EventSubscriptionAdded",
++ "REDFISH_MESSAGE_ARGS=%s", id.c_str(), NULL);
++
+ return id;
+ }
+
+@@ -1027,7 +1035,14 @@ class EventServiceManager
+ {
+ subscriptionsMap.erase(obj);
+ updateNoOfSubscribersCount();
+- updateSubscriptionData();
++
++ persistSubscriptionData();
++ /* Log event for subscription delete. */
++ sd_journal_send("MESSAGE=Event subscription removed.(Id = %s)",
++ id.c_str(), "PRIORITY=%i", LOG_INFO,
++ "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.EventSubscriptionRemoved",
++ "REDFISH_MESSAGE_ARGS=%s", id.c_str(), NULL);
+ }
+ }
+
+@@ -1049,6 +1064,18 @@ class EventServiceManager
+ }
+ }
+
++ void updateSubscription(const std::string& id)
++ {
++ persistSubscriptionData();
++
++ /* Log event for subscription update. */
++ sd_journal_send("MESSAGE=Event subscription updated.(Id = %s)",
++ id.c_str(), "PRIORITY=%i", LOG_INFO,
++ "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.EventSubscriptionUpdated",
++ "REDFISH_MESSAGE_ARGS=%s", id.c_str(), NULL);
++ }
++
+ size_t getNumberOfSubscriptions()
+ {
+ return subscriptionsMap.size();
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index 297a4ea..ed4955e 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -616,7 +616,7 @@ class EventDestination : public Node
+ subValue->updateRetryPolicy();
+ }
+
+- EventServiceManager::getInstance().updateSubscriptionData();
++ EventServiceManager::getInstance().updateSubscription(params[0]);
+ }
+
+ void doDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch
new file mode 100644
index 000000000..874c82e2f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch
@@ -0,0 +1,85 @@
+From b43da33c7bc9ad4d5eea35c9ba68efdd6ed6d34d Mon Sep 17 00:00:00 2001
+From: Nitin Wankhade <nitinx.arunrao.wankhade@intel.com>
+Date: Mon, 28 Jun 2021 19:59:57 +0000
+Subject: [PATCH] Add checks on Event Subscription input parameters
+
+There is no check on the size of input parameters(Context,
+Destination and Header) during Event Subscription.This
+creates out of memory situation.
+This commit checks for the size of input parameters and
+rejects if it is exceeding the input size limits.
+
+Tested
+ - Validated using POST on Event Subscription.
+ - When Context, Destination and Headers were too long,
+ received a error message denoting the same.
+
+Change-Id: Iec2cd766c0e137b72706fc2da468d4fefd8fbaae
+Signed-off-by: Nitin Wankhade <nitinx.arunrao.wankhade@intel.com>
+---
+ redfish-core/lib/event_service.hpp | 30 +++++++++++++++++++++++++++++-
+ 1 file changed, 29 insertions(+), 1 deletion(-)
+
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index ed4955e..0cb0f00 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -16,6 +16,10 @@
+ #pragma once
+ #include "event_service_manager.hpp"
+
++#define MAX_CONTEXT_SIZE 256
++#define MAX_DESTINATION_SIZE 1024
++#define MAX_HEADER_SIZE 8096
++
+ namespace redfish
+ {
+ static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
+@@ -243,7 +247,11 @@ class EventDestinationCollection : public Node
+ {
+ return;
+ }
+-
++ if (destUrl.size() > MAX_DESTINATION_SIZE)
++ {
++ messages::propertySizeExceeded(asyncResp->res, "Destination");
++ return;
++ }
+ if (regPrefixes && msgIds)
+ {
+ if (regPrefixes->size() && msgIds->size())
+@@ -350,11 +358,31 @@ class EventDestinationCollection : public Node
+
+ if (context)
+ {
++ if (context->size() > MAX_CONTEXT_SIZE)
++ {
++ messages::propertySizeExceeded(asyncResp->res, "Context");
++ return;
++ }
+ subValue->customText = *context;
+ }
+
+ if (headers)
+ {
++ size_t cumulativeLen = 0;
++
++ for (nlohmann::json& itr : *headers)
++ {
++ std::string hdr{itr.dump(
++ -1, ' ', true, nlohmann::json::error_handler_t::replace)};
++ cumulativeLen += hdr.length();
++
++ if (cumulativeLen > MAX_HEADER_SIZE)
++ {
++ messages::propertySizeExceeded(asyncResp->res,
++ "HttpHeaders");
++ return;
++ }
++ }
+ subValue->httpHeaders = *headers;
+ }
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README
new file mode 100644
index 000000000..ae010dafb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README
@@ -0,0 +1,19 @@
+Eventservice specific patches: Temporary pulling down
+the upstream patches. These will be remove as soon as
+thee gets merged upstream.
+
+Upstream revision information:
+ - EventService : Fix retry handling for http-client
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/40731/20
+
+ - EventService: https client support
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/31735/39
+
+ - Add Server-Sent-Events support
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41258/6
+
+ - Add SSE style subscription support to eventservice
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41319/6
+
+ - Add EventService SSE filter support
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41349/3
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch
new file mode 100644
index 000000000..f03e49223
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch
@@ -0,0 +1,491 @@
+From 6acffea563905c00f4b6d00c738fe7516e03c724 Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Tue, 13 Apr 2021 13:00:18 +0000
+Subject: [PATCH] Add support for MetricDefinition scheme
+
+Added MetricDefinition node to Redfish code. Now user is able to list
+all available metrics in OpenBMC that are supported by Telemetry
+service. Metrics are grouped by following categories: temperature,
+power, voltage, current, fan_tach, fan_pwm, utilization.
+
+Tested:
+ - MetricDefinitions response is filled with existing sensors, it works
+ with and without Telemetry service
+ - Validated a presence of MetricDefinition members and its attributes
+ - Successfully passed RedfishServiceValidator.py using witherspoon image
+ on QEMU
+
+Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
+Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Change-Id: I3086e1302e1ba2e5442d1367939fd5507a0cbc00
+---
+ redfish-core/include/redfish.hpp | 3 +
+ .../include/utils/get_chassis_names.hpp | 58 ++++
+ .../include/utils/telemetry_utils.hpp | 2 +
+ redfish-core/lib/metric_definition.hpp | 264 ++++++++++++++++++
+ redfish-core/lib/sensors.hpp | 25 +-
+ redfish-core/lib/telemetry_service.hpp | 2 +
+ 6 files changed, 342 insertions(+), 12 deletions(-)
+ create mode 100644 redfish-core/include/utils/get_chassis_names.hpp
+ create mode 100644 redfish-core/lib/metric_definition.hpp
+
+diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
+index 4418c3d..594520d 100644
+--- a/redfish-core/include/redfish.hpp
++++ b/redfish-core/include/redfish.hpp
+@@ -25,6 +25,7 @@
+ #include "../lib/managers.hpp"
+ #include "../lib/memory.hpp"
+ #include "../lib/message_registries.hpp"
++#include "../lib/metric_definition.hpp"
+ #include "../lib/metric_report.hpp"
+ #include "../lib/metric_report_definition.hpp"
+ #include "../lib/network_protocol.hpp"
+@@ -215,6 +216,8 @@ class RedfishService
+ nodes.emplace_back(std::make_unique<HypervisorResetActionInfo>(app));
+
+ nodes.emplace_back(std::make_unique<TelemetryService>(app));
++ nodes.emplace_back(std::make_unique<MetricDefinitionCollection>(app));
++ nodes.emplace_back(std::make_unique<MetricDefinition>(app));
+ nodes.emplace_back(
+ std::make_unique<MetricReportDefinitionCollection>(app));
+ nodes.emplace_back(std::make_unique<MetricReportDefinition>(app));
+diff --git a/redfish-core/include/utils/get_chassis_names.hpp b/redfish-core/include/utils/get_chassis_names.hpp
+new file mode 100644
+index 0000000..0276b6f
+--- /dev/null
++++ b/redfish-core/include/utils/get_chassis_names.hpp
+@@ -0,0 +1,58 @@
++#pragma once
++
++#include <include/dbus_singleton.hpp>
++
++#include <array>
++#include <string>
++#include <vector>
++
++namespace redfish
++{
++
++namespace utils
++{
++
++template <typename F>
++inline void getChassisNames(F&& cb)
++{
++ const std::array<const char*, 2> interfaces = {
++ "xyz.openbmc_project.Inventory.Item.Board",
++ "xyz.openbmc_project.Inventory.Item.Chassis"};
++
++ crow::connections::systemBus->async_method_call(
++ [callback = std::move(cb)](const boost::system::error_code ec,
++ const std::vector<std::string>& chassis) {
++ std::vector<std::string> chassisNames;
++
++ if (ec)
++ {
++ callback(ec, chassisNames);
++ return;
++ }
++
++ chassisNames.reserve(chassis.size());
++ for (const std::string& path : chassis)
++ {
++ sdbusplus::message::object_path dbusPath = path;
++ std::string name = dbusPath.filename();
++ if (name.empty())
++ {
++ callback(boost::system::errc::make_error_code(
++ boost::system::errc::invalid_argument),
++ chassisNames);
++ return;
++ }
++ chassisNames.emplace_back(std::move(name));
++ }
++
++ callback(ec, chassisNames);
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
++ "/xyz/openbmc_project/inventory", 0, interfaces);
++}
++
++} // namespace utils
++
++} // namespace redfish
+diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp
+index 5872350..1b4f75d 100644
+--- a/redfish-core/include/utils/telemetry_utils.hpp
++++ b/redfish-core/include/utils/telemetry_utils.hpp
+@@ -10,6 +10,8 @@ namespace telemetry
+
+ constexpr const char* service = "xyz.openbmc_project.Telemetry";
+ constexpr const char* reportInterface = "xyz.openbmc_project.Telemetry.Report";
++constexpr const char* metricDefinitionUri =
++ "/redfish/v1/TelemetryService/MetricDefinitions/";
+ constexpr const char* metricReportDefinitionUri =
+ "/redfish/v1/TelemetryService/MetricReportDefinitions/";
+ constexpr const char* metricReportUri =
+diff --git a/redfish-core/lib/metric_definition.hpp b/redfish-core/lib/metric_definition.hpp
+new file mode 100644
+index 0000000..072fe20
+--- /dev/null
++++ b/redfish-core/lib/metric_definition.hpp
+@@ -0,0 +1,264 @@
++#pragma once
++
++#include "async_resp.hpp"
++#include "node.hpp"
++#include "sensors.hpp"
++#include "utils/get_chassis_names.hpp"
++#include "utils/telemetry_utils.hpp"
++
++namespace redfish
++{
++
++namespace telemetry
++{
++
++void addMembers(crow::Response& res,
++ const boost::container::flat_map<std::string, std::string>& el)
++{
++ for (const auto& [_, dbusSensor] : el)
++ {
++ sdbusplus::message::object_path path(dbusSensor);
++ sdbusplus::message::object_path parentPath = path.parent_path();
++ const std::string type = parentPath.filename();
++
++ if (type.empty())
++ {
++ BMCWEB_LOG_ERROR << "Received invalid DBus Sensor Path = "
++ << dbusSensor;
++ continue;
++ }
++
++ nlohmann::json& members = res.jsonValue["Members"];
++
++ const std::string odataId =
++ std::string(telemetry::metricDefinitionUri) +
++ sensors::toReadingType(type);
++
++ const auto it = std::find_if(members.begin(), members.end(),
++ [&odataId](const nlohmann::json& item) {
++ auto kt = item.find("@odata.id");
++ if (kt == item.end())
++ {
++ return false;
++ }
++ const std::string* value =
++ kt->get_ptr<const std::string*>();
++ if (!value)
++ {
++ return false;
++ }
++ return *value == odataId;
++ });
++
++ if (it == members.end())
++ {
++ members.push_back({{"@odata.id", odataId}});
++ }
++
++ res.jsonValue["Members@odata.count"] = members.size();
++ }
++}
++
++} // namespace telemetry
++
++class MetricDefinitionCollection : public Node
++{
++ public:
++ MetricDefinitionCollection(App& app) :
++ Node(app, "/redfish/v1/TelemetryService/MetricDefinitions/")
++ {
++ entityPrivileges = {
++ {boost::beast::http::verb::get, {{"Login"}}},
++ {boost::beast::http::verb::head, {{"Login"}}},
++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
++ }
++
++ private:
++ void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const crow::Request&, const std::vector<std::string>&) override
++ {
++ asyncResp->res.jsonValue["@odata.type"] = "#MetricDefinitionCollection."
++ "MetricDefinitionCollection";
++ asyncResp->res.jsonValue["@odata.id"] =
++ "/redfish/v1/TelemetryService/MetricDefinitions";
++ asyncResp->res.jsonValue["Name"] = "Metric Definition Collection";
++ asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
++ asyncResp->res.jsonValue["Members@odata.count"] = 0;
++
++ utils::getChassisNames(
++ [asyncResp](boost::system::error_code ec,
++ const std::vector<std::string>& chassisNames) {
++ if (ec)
++ {
++ messages::internalError(asyncResp->res);
++ BMCWEB_LOG_ERROR << "getChassisNames error: " << ec.value();
++ return;
++ }
++
++ auto handleRetrieveUriToDbusMap =
++ [asyncResp](const boost::beast::http::status status,
++ const boost::container::flat_map<
++ std::string, std::string>& uriToDbus) {
++ if (status != boost::beast::http::status::ok)
++ {
++ BMCWEB_LOG_ERROR
++ << "Failed to retrieve URI to dbus "
++ "sensors map with err "
++ << static_cast<unsigned>(status);
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ telemetry::addMembers(asyncResp->res, uriToDbus);
++ };
++
++ for (const std::string& chassisName : chassisNames)
++ {
++ for (const auto& [sensorNode, _] : sensors::dbus::paths)
++ {
++ BMCWEB_LOG_DEBUG << "Chassis: " << chassisName
++ << " sensor: " << sensorNode;
++ retrieveUriToDbusMap(chassisName, sensorNode.data(),
++ handleRetrieveUriToDbusMap);
++ }
++ }
++ });
++ }
++};
++
++namespace telemetry
++{
++
++bool isSensorIdSupported(std::string_view readingType)
++{
++ for (const std::pair<std::string_view, std::vector<const char*>>&
++ typeToPaths : sensors::dbus::paths)
++ {
++ for (const char* supportedPath : typeToPaths.second)
++ {
++ if (readingType ==
++ sensors::toReadingType(
++ sdbusplus::message::object_path(supportedPath).filename()))
++ {
++ return true;
++ }
++ }
++ }
++ return false;
++}
++
++void addMetricProperty(
++ bmcweb::AsyncResp& asyncResp, const std::string& readingType,
++ const boost::container::flat_map<std::string, std::string>& el)
++{
++ nlohmann::json& metricProperties =
++ asyncResp.res.jsonValue["MetricProperties"];
++
++ for (const auto& [redfishSensor, dbusSensor] : el)
++ {
++ std::string sensorId;
++ if (dbus::utility::getNthStringFromPath(dbusSensor, 3, sensorId))
++ {
++ if (sensors::toReadingType(sensorId) == readingType)
++ {
++ metricProperties.push_back(redfishSensor);
++ }
++ }
++ }
++}
++
++} // namespace telemetry
++
++class MetricDefinition : public Node
++{
++ public:
++ MetricDefinition(App& app) :
++ Node(app, "/redfish/v1/TelemetryService/MetricDefinitions/<str>/",
++ std::string())
++ {
++ entityPrivileges = {
++ {boost::beast::http::verb::get, {{"Login"}}},
++ {boost::beast::http::verb::head, {{"Login"}}},
++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
++ }
++
++ private:
++ void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const crow::Request&,
++ const std::vector<std::string>& params) override
++ {
++ if (params.size() != 1)
++ {
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ const std::string& readingType = params[0];
++
++ if (!telemetry::isSensorIdSupported(readingType))
++ {
++ messages::resourceNotFound(asyncResp->res, "MetricDefinition",
++ readingType);
++ return;
++ }
++
++ asyncResp->res.jsonValue["MetricProperties"] = nlohmann::json::array();
++ asyncResp->res.jsonValue["Id"] = readingType;
++ asyncResp->res.jsonValue["Name"] = readingType;
++ asyncResp->res.jsonValue["@odata.id"] =
++ telemetry::metricDefinitionUri + readingType;
++ asyncResp->res.jsonValue["@odata.type"] =
++ "#MetricDefinition.v1_0_3.MetricDefinition";
++ asyncResp->res.jsonValue["MetricDataType"] = "Decimal";
++ asyncResp->res.jsonValue["MetricType"] = "Numeric";
++ asyncResp->res.jsonValue["IsLinear"] = true;
++ asyncResp->res.jsonValue["Implementation"] = "PhysicalSensor";
++ asyncResp->res.jsonValue["Units"] =
++ sensors::toReadingUnits(readingType);
++
++ utils::getChassisNames([asyncResp,
++ readingType](boost::system::error_code ec,
++ const std::vector<std::string>&
++ chassisNames) {
++ if (ec)
++ {
++ messages::internalError(asyncResp->res);
++ BMCWEB_LOG_ERROR << "getChassisNames error: " << ec.value();
++ return;
++ }
++
++ auto handleRetrieveUriToDbusMap =
++ [asyncResp, readingType](
++ const boost::beast::http::status status,
++ const boost::container::flat_map<std::string, std::string>&
++ uriToDbus) {
++ if (status != boost::beast::http::status::ok)
++ {
++ BMCWEB_LOG_ERROR << "Failed to retrieve URI to dbus "
++ "sensors map with err "
++ << static_cast<unsigned>(status);
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ telemetry::addMetricProperty(*asyncResp, readingType,
++ uriToDbus);
++ };
++
++ for (const std::string& chassisName : chassisNames)
++ {
++ for (const auto& [sensorNode, dbusPaths] : sensors::dbus::paths)
++ {
++ retrieveUriToDbusMap(chassisName, sensorNode.data(),
++ handleRetrieveUriToDbusMap);
++ }
++ }
++ });
++ }
++};
++
++} // namespace redfish
+diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
+index e7f4cde..b16b014 100644
+--- a/redfish-core/lib/sensors.hpp
++++ b/redfish-core/lib/sensors.hpp
+@@ -111,46 +111,47 @@ inline const char* toReadingType(const std::string& sensorType)
+ return "";
+ }
+
+-inline const char* toReadingUnits(const std::string& sensorType)
++inline const char* toReadingUnits(const std::string& readingType)
+ {
+- if (sensorType == "voltage")
++ if (readingType == "Voltage")
+ {
+ return "V";
+ }
+- if (sensorType == "power")
++ if (readingType == "Power")
+ {
+ return "W";
+ }
+- if (sensorType == "current")
++ if (readingType == "Current")
+ {
+ return "A";
+ }
+- if (sensorType == "fan_tach")
++ if (readingType == "Rotational")
+ {
+ return "RPM";
+ }
+- if (sensorType == "temperature")
++ if (readingType == "Temperature")
+ {
+ return "Cel";
+ }
+- if (sensorType == "fan_pwm" || sensorType == "utilization")
++ if (readingType == "Percent")
+ {
+ return "%";
+ }
+- if (sensorType == "altitude")
++ if (readingType == "Altitude")
+ {
+ return "m";
+ }
+- if (sensorType == "airflow")
++ if (readingType == "AirFlow")
+ {
+ return "cft_i/min";
+ }
+- if (sensorType == "energy")
++ if (readingType == "EnergyJoules")
+ {
+ return "J";
+ }
+ return "";
+ }
++
+ } // namespace sensors
+
+ /**
+@@ -953,11 +954,11 @@ inline void objectInterfacesToJson(
+ sensorJson["ReadingType"] = readingType;
+ }
+
+- const std::string& readingUnits = sensors::toReadingUnits(sensorType);
++ const std::string& readingUnits = sensors::toReadingUnits(readingType);
+ if (readingUnits.empty())
+ {
+ BMCWEB_LOG_ERROR << "Redfish cannot map reading unit for "
+- << sensorType;
++ << readingType;
+ }
+ else
+ {
+diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp
+index 9ec0737..de9c800 100644
+--- a/redfish-core/lib/telemetry_service.hpp
++++ b/redfish-core/lib/telemetry_service.hpp
+@@ -32,6 +32,8 @@ class TelemetryService : public Node
+ asyncResp->res.jsonValue["Id"] = "TelemetryService";
+ asyncResp->res.jsonValue["Name"] = "Telemetry Service";
+
++ asyncResp->res.jsonValue["MetricDefinitions"]["@odata.id"] =
++ "/redfish/v1/TelemetryService/MetricDefinitions";
+ asyncResp->res.jsonValue["MetricReportDefinitions"]["@odata.id"] =
+ "/redfish/v1/TelemetryService/MetricReportDefinitions";
+ asyncResp->res.jsonValue["MetricReports"]["@odata.id"] =
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch
new file mode 100644
index 000000000..9b77c29df
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch
@@ -0,0 +1,294 @@
+From 206411b4c9b603e7b0edf63e03c0ef7bf10b09b2 Mon Sep 17 00:00:00 2001
+From: "Wludzik, Jozef" <jozef.wludzik@intel.com>
+Date: Tue, 15 Dec 2020 12:30:31 +0100
+Subject: [PATCH] Sync Telmetry service with EventService
+
+Synced the latest changes in Telemetry service with Event Service
+code. Now assembling MetricReport is covered in single place in
+code. Updated method of fetching Readings from Telemetry by
+Event Service. Using ReportUpdate signal is no longer
+supported. Now Event Service monitors for PropertiesChanged signal
+from /xyz/openbmc_project/Telemetry/Reports path.
+
+Tested:
+ - Verified that EventListener received MetricReport response from
+ Event Service in insecure http push style eventing mode
+
+Change-Id: I2fc1841a6c9259a8bff30b34bddc0d4aabd41912
+Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
+---
+ .../include/event_service_manager.hpp | 156 ++++++------------
+ redfish-core/lib/metric_report.hpp | 28 ++--
+ 2 files changed, 69 insertions(+), 115 deletions(-)
+
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index a1761bb..0e2ebfd 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -14,6 +14,7 @@
+ // limitations under the License.
+ */
+ #pragma once
++#include "metric_report.hpp"
+ #include "node.hpp"
+ #include "registries.hpp"
+ #include "registries/base_message_registry.hpp"
+@@ -523,47 +524,32 @@ class Subscription
+ }
+ #endif
+
+- void filterAndSendReports(const std::string& id2,
+- const std::string& readingsTs,
+- const ReadingsObjType& readings)
++ void filterAndSendReports(
++ const std::string& id,
++ const std::variant<telemetry::TimestampReadings>& var)
+ {
+- std::string metricReportDef =
+- "/redfish/v1/TelemetryService/MetricReportDefinitions/" + id2;
++ std::string mrdUri = telemetry::metricReportDefinitionUri + id;
+
+ // Empty list means no filter. Send everything.
+ if (metricReportDefinitions.size())
+ {
+ if (std::find(metricReportDefinitions.begin(),
+ metricReportDefinitions.end(),
+- metricReportDef) == metricReportDefinitions.end())
++ mrdUri) == metricReportDefinitions.end())
+ {
+ return;
+ }
+ }
+
+- nlohmann::json metricValuesArray = nlohmann::json::array();
+- for (const auto& it : readings)
++ nlohmann::json msg;
++ if (!telemetry::fillReport(msg, id, var))
+ {
+- metricValuesArray.push_back({});
+- nlohmann::json& entry = metricValuesArray.back();
+-
+- auto& [id, property, value, timestamp] = it;
+-
+- entry = {{"MetricId", id},
+- {"MetricProperty", property},
+- {"MetricValue", std::to_string(value)},
+- {"Timestamp", crow::utility::getDateTime(timestamp)}};
++ BMCWEB_LOG_ERROR << "Failed to fill the MetricReport for DBus "
++ "Report with id "
++ << id;
++ return;
+ }
+
+- nlohmann::json msg = {
+- {"@odata.id", "/redfish/v1/TelemetryService/MetricReports/" + id},
+- {"@odata.type", "#MetricReport.v1_3_0.MetricReport"},
+- {"Id", id2},
+- {"Name", id2},
+- {"Timestamp", readingsTs},
+- {"MetricReportDefinition", {{"@odata.id", metricReportDef}}},
+- {"MetricValues", metricValuesArray}};
+-
+ this->sendEvent(
+ msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace));
+ }
+@@ -1359,75 +1345,6 @@ class EventServiceManager
+ }
+
+ #endif
+-
+- void getMetricReading(const std::string& service,
+- const std::string& objPath, const std::string& intf)
+- {
+- std::size_t found = objPath.find_last_of('/');
+- if (found == std::string::npos)
+- {
+- BMCWEB_LOG_DEBUG << "Invalid objPath received";
+- return;
+- }
+-
+- std::string idStr = objPath.substr(found + 1);
+- if (idStr.empty())
+- {
+- BMCWEB_LOG_DEBUG << "Invalid ID in objPath";
+- return;
+- }
+-
+- crow::connections::systemBus->async_method_call(
+- [idStr{std::move(idStr)}](
+- const boost::system::error_code ec,
+- boost::container::flat_map<
+- std::string, std::variant<int32_t, ReadingsObjType>>&
+- resp) {
+- if (ec)
+- {
+- BMCWEB_LOG_DEBUG
+- << "D-Bus call failed to GetAll metric readings.";
+- return;
+- }
+-
+- const int32_t* timestampPtr =
+- std::get_if<int32_t>(&resp["Timestamp"]);
+- if (!timestampPtr)
+- {
+- BMCWEB_LOG_DEBUG << "Failed to Get timestamp.";
+- return;
+- }
+-
+- ReadingsObjType* readingsPtr =
+- std::get_if<ReadingsObjType>(&resp["Readings"]);
+- if (!readingsPtr)
+- {
+- BMCWEB_LOG_DEBUG << "Failed to Get Readings property.";
+- return;
+- }
+-
+- if (!readingsPtr->size())
+- {
+- BMCWEB_LOG_DEBUG << "No metrics report to be transferred";
+- return;
+- }
+-
+- for (const auto& it :
+- EventServiceManager::getInstance().subscriptionsMap)
+- {
+- std::shared_ptr<Subscription> entry = it.second;
+- if (entry->eventFormatType == metricReportFormatType)
+- {
+- entry->filterAndSendReports(
+- idStr, crow::utility::getDateTime(*timestampPtr),
+- *readingsPtr);
+- }
+- }
+- },
+- service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
+- intf);
+- }
+-
+ void unregisterMetricReportSignal()
+ {
+ if (matchTelemetryMonitor)
+@@ -1447,9 +1364,11 @@ class EventServiceManager
+ }
+
+ BMCWEB_LOG_DEBUG << "Metrics report signal - Register";
+- std::string matchStr(
+- "type='signal',member='ReportUpdate', "
+- "interface='xyz.openbmc_project.MonitoringService.Report'");
++ std::string matchStr = "type='signal',member='PropertiesChanged',"
++ "interface='org.freedesktop.DBus.Properties',"
++ "path_namespace=/xyz/openbmc_project/Telemetry/"
++ "Reports/TelemetryService,"
++ "arg0=xyz.openbmc_project.Telemetry.Report";
+
+ matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus, matchStr,
+@@ -1460,10 +1379,43 @@ class EventServiceManager
+ return;
+ }
+
+- std::string service = msg.get_sender();
+- std::string objPath = msg.get_path();
+- std::string intf = msg.get_interface();
+- getMetricReading(service, objPath, intf);
++ sdbusplus::message::object_path path(msg.get_path());
++ std::string id = path.filename();
++ if (id.empty())
++ {
++ BMCWEB_LOG_ERROR << "Failed to get Id from path";
++ return;
++ }
++
++ std::string intf;
++ std::vector<std::pair<
++ std::string, std::variant<telemetry::TimestampReadings>>>
++ props;
++ std::vector<std::string> invalidProps;
++ msg.read(intf, props, invalidProps);
++
++ auto found =
++ std::find_if(props.begin(), props.end(), [](const auto& x) {
++ return x.first == "Readings";
++ });
++ if (found == props.end())
++ {
++ BMCWEB_LOG_ERROR
++ << "Failed to get Readings from Report properties";
++ return;
++ }
++
++ std::variant<telemetry::TimestampReadings>& readings =
++ found->second;
++ for (const auto& it :
++ EventServiceManager::getInstance().subscriptionsMap)
++ {
++ Subscription& entry = *it.second.get();
++ if (entry.eventFormatType == metricReportFormatType)
++ {
++ entry.filterAndSendReports(id, readings);
++ }
++ }
+ });
+ }
+
+diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp
+index ad15a05..18a6dcc 100644
+--- a/redfish-core/lib/metric_report.hpp
++++ b/redfish-core/lib/metric_report.hpp
+@@ -31,16 +31,14 @@ inline nlohmann::json toMetricValues(const Readings& readings)
+ return metricValues;
+ }
+
+-inline void fillReport(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+- const std::string& id,
++inline bool fillReport(nlohmann::json& json, const std::string& id,
+ const std::variant<TimestampReadings>& var)
+ {
+- asyncResp->res.jsonValue["@odata.type"] =
+- "#MetricReport.v1_3_0.MetricReport";
+- asyncResp->res.jsonValue["@odata.id"] = telemetry::metricReportUri + id;
+- asyncResp->res.jsonValue["Id"] = id;
+- asyncResp->res.jsonValue["Name"] = id;
+- asyncResp->res.jsonValue["MetricReportDefinition"]["@odata.id"] =
++ json["@odata.type"] = "#MetricReport.v1_3_0.MetricReport";
++ json["@odata.id"] = telemetry::metricReportUri + id;
++ json["Id"] = id;
++ json["Name"] = id;
++ json["MetricReportDefinition"]["@odata.id"] =
+ telemetry::metricReportDefinitionUri + id;
+
+ const TimestampReadings* timestampReadings =
+@@ -48,14 +46,14 @@ inline void fillReport(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ if (!timestampReadings)
+ {
+ BMCWEB_LOG_ERROR << "Property type mismatch or property is missing";
+- messages::internalError(asyncResp->res);
+- return;
++ return false;
+ }
+
+ const auto& [timestamp, readings] = *timestampReadings;
+- asyncResp->res.jsonValue["Timestamp"] =
++ json["Timestamp"] =
+ crow::utility::getDateTime(static_cast<time_t>(timestamp));
+- asyncResp->res.jsonValue["MetricValues"] = toMetricValues(readings);
++ json["MetricValues"] = toMetricValues(readings);
++ return true;
+ }
+ } // namespace telemetry
+
+@@ -145,7 +143,11 @@ class MetricReport : public Node
+ return;
+ }
+
+- telemetry::fillReport(asyncResp, id, ret);
++ if (!telemetry::fillReport(asyncResp->res.jsonValue, id,
++ ret))
++ {
++ messages::internalError(asyncResp->res);
++ }
+ },
+ telemetry::service, reportPath,
+ "org.freedesktop.DBus.Properties", "Get",
+--
+2.25.1
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Revert-Remove-LogService-from-TelemetryService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Revert-Remove-LogService-from-TelemetryService.patch
new file mode 100644
index 000000000..645351a51
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Revert-Remove-LogService-from-TelemetryService.patch
@@ -0,0 +1,26 @@
+From dc7e43c70285596195efd9d328b303091794278c Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Mon, 31 May 2021 10:08:57 +0000
+Subject: [PATCH] Revert "Remove LogService from TelemetryService"
+
+This reverts commit 2b3da45876aac57a36d3093379a992d699e7e396.
+---
+ redfish-core/lib/telemetry_service.hpp | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp
+index de9c800..f05bf6d 100644
+--- a/redfish-core/lib/telemetry_service.hpp
++++ b/redfish-core/lib/telemetry_service.hpp
+@@ -38,6 +38,8 @@ class TelemetryService : public Node
+ "/redfish/v1/TelemetryService/MetricReportDefinitions";
+ asyncResp->res.jsonValue["MetricReports"]["@odata.id"] =
+ "/redfish/v1/TelemetryService/MetricReports";
++ asyncResp->res.jsonValue["LogService"]["@odata.id"] =
++ "/redfish/v1/Managers/bmc/LogServices/Journal";
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-event-service-fix-added-Context-field-to-response.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-event-service-fix-added-Context-field-to-response.patch
new file mode 100644
index 000000000..ffab743f6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-event-service-fix-added-Context-field-to-response.patch
@@ -0,0 +1,29 @@
+From 0ca8c383db8c9afbce63380955a20ada0acc20b7 Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Wed, 2 Jun 2021 12:44:43 +0000
+Subject: [PATCH] event service fix, added Context field to response
+
+Tested:
+ - Context field is present
+ - No regression detected
+
+Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+---
+ redfish-core/include/event_service_manager.hpp | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 2b957ea..289886b 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -556,6 +556,7 @@ class Subscription
+ << id;
+ return;
+ }
++ msg["Context"] = customText;
+
+ this->sendEvent(
+ msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace));
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README
new file mode 100644
index 000000000..ea6ac73bd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README
@@ -0,0 +1,15 @@
+These patches are mirror of upstream TelemetryService implementation.
+Until change is integrated they will be manually merged here to enable feature in Intel builds.
+
+Current revisions:
+- Add support for MetricDefinition scheme
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/33363/80
+
+- Sync Telmetry service with EventService
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/38798/31
+
+- LogService field, actual implementation will be upstreamed with triggers feature
+ file://telemetry/0003-Revert-Remove-LogService-from-TelemetryService.patch
+
+- Event service fix for Context field
+ file://telemetry/0004-event-service-fix-added-Context-field-to-response.patch
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0001-Revert-Disable-nbd-proxy-from-the-build.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0001-Revert-Disable-nbd-proxy-from-the-build.patch
new file mode 100644
index 000000000..3e3f69d1c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0001-Revert-Disable-nbd-proxy-from-the-build.patch
@@ -0,0 +1,50 @@
+From 95f002dc969d7d6d64dbf2ee0db7dc1c1c6a9173 Mon Sep 17 00:00:00 2001
+From: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com>
+Date: Thu, 18 Mar 2021 11:30:28 +0100
+Subject: [PATCH] Revert "Disable nbd proxy from the build"
+
+NBD Proxy has been disabled upstream. Reenable as we use it for Virtual
+Media
+
+This reverts commit efb8062c306474942bc94f15d748b2eb0b58fbb6.
+---
+ meson.build | 2 +-
+ meson_options.txt | 9 +--------
+ 2 files changed, 2 insertions(+), 9 deletions(-)
+
+diff --git a/meson.build b/meson.build
+index 66a066b..cef0a49 100644
+--- a/meson.build
++++ b/meson.build
+@@ -81,7 +81,7 @@ feature_map = {
+ 'static-hosting' : '-DBMCWEB_ENABLE_STATIC_HOSTING',
+ 'insecure-tftp-update' : '-DBMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE',
+ 'validate-unsecure-feature' : '-DBMCWEB_ENABLE_VALIDATION_UNSECURE_FEATURE',
+-#'vm-nbdproxy' : '-DBMCWEB_ENABLE_VM_NBDPROXY',
++'vm-nbdproxy' : '-DBMCWEB_ENABLE_VM_NBDPROXY',
+ 'vm-websocket' : '-DBMCWEB_ENABLE_VM_WEBSOCKET',
+ }
+
+diff --git a/meson_options.txt b/meson_options.txt
+index 9611631..7ee3ebb 100644
+--- a/meson_options.txt
++++ b/meson_options.txt
+@@ -3,14 +3,7 @@ option('yocto-deps', type: 'feature', value: 'disabled', description : 'Use YOCT
+ option('kvm', type : 'feature',value : 'enabled', description : 'Enable the KVM host video WebSocket. Path is \'/kvm/0\'. Video is from the BMC\'s \'/dev/video\' device.')
+ option ('tests', type : 'feature', value : 'enabled', description : 'Enable Unit tests for bmcweb')
+ option('vm-websocket', type : 'feature', value : 'enabled', description : '''Enable the Virtual Media WebSocket. Path is \'/vm/0/0\'to open the websocket. See https://github.com/openbmc/jsnbd/blob/master/README.''')
+-
+-# if you use this option and are seeing this comment, please comment here:
+-# https://github.com/openbmc/bmcweb/issues/188 and put forward your intentions
+-# for this code. At this point, no daemon has been upstreamed that implements
+-# this interface, so for the moment this appears to be dead code; In leiu of
+-# removing it, it has been disabled to try to give those that use it the
+-# opportunity to upstream their backend implementation
+-#option('vm-nbdproxy', type: 'feature', value : 'disabled', description : 'Enable the Virtual Media WebSocket.')
++option('vm-nbdproxy', type: 'feature', value : 'disabled', description : 'Enable the Virtual Media WebSocket.')
+ option('rest', type : 'feature', value : 'enabled', description : '''Enable Phosphor REST (D-Bus) APIs. Paths directly map Phosphor D-Bus object paths, for example, \'/xyz/openbmc_project/logging/entry/enumerate\'. See https://github.com/openbmc/docs/blob/master/rest-api.md.''')
+ option('redfish', type : 'feature',value : 'enabled', description: 'Enable Redfish APIs. Paths are under \'/redfish/v1/\'. See https://github.com/openbmc/bmcweb/blob/master/DEVELOPING.md#redfish.')
+ option('host-serial-socket', type : 'feature', value : 'enabled', description : 'Enable host serial console WebSocket. Path is \'/console0\'. See https://github.com/openbmc/docs/blob/master/console.md.')
+--
+2.26.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0002-bmcweb-handle-device-or-resource-busy-exception.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0002-bmcweb-handle-device-or-resource-busy-exception.patch
new file mode 100644
index 000000000..01c1c858c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0002-bmcweb-handle-device-or-resource-busy-exception.patch
@@ -0,0 +1,219 @@
+From 76480c6a5b1708113f28aecab32a85984371243c Mon Sep 17 00:00:00 2001
+From: Karol Wachowski <karol.wachowski@intel.com>
+Date: Fri, 10 Jul 2020 09:54:06 +0000
+Subject: [PATCH] bmcweb handle device or resource busy exception
+
+Use async_method_call_timed() for mount/unmount dbus oprations.
+Long mount/unmount times are supported by VirtualMedia service,
+this works because of settable timeout property, available for each block
+device.
+Default dbus calls will timeout when mount/unmount timeout is long enough.
+
+Get mount/unmount timeout property and use it for mount/unmount calls.
+Add handling of device or resource busy exception (EBUSY) that
+can be thrown by VirtualMedia service during Mount/Unmount dbus operations.
+
+Tested: Verified that after mounting non-existing HTTPS resource
+ in proxy mode, VirtualMedia recovers restoring ready state
+ and returns EBUSY during that transition.
+ Verfied that resources can be mounted/unmounted in both legacy
+ and proxy mode.
+Signed-off-by: Karol Wachowski <karol.wachowski@intel.com>
+Change-Id: Ica62c34db0cce24c4c6169fc661edfde49e948d0
+---
+ redfish-core/lib/virtual_media.hpp | 144 ++++++++++++++++++++++-------
+ 1 file changed, 110 insertions(+), 34 deletions(-)
+
+diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp
+index 95a8881..188248a 100644
+--- a/redfish-core/lib/virtual_media.hpp
++++ b/redfish-core/lib/virtual_media.hpp
+@@ -24,6 +24,8 @@
+ #include <account_service.hpp>
+ #include <boost/url/url_view.hpp>
+
++#include <chrono>
++
+ namespace redfish
+
+ {
+@@ -160,6 +162,26 @@ static void vmParseInterfaceObject(const DbusInterfaceType& interface,
+ }
+ }
+
++/**
++ * @brief parses Timeout property and converts to microseconds
++ */
++static std::optional<uint64_t>
++ vmParseTimeoutProperty(const std::variant<int>& timeoutProperty)
++{
++ const int* timeoutValue = std::get_if<int>(&timeoutProperty);
++ if (timeoutValue)
++ {
++ constexpr int timeoutMarginSeconds = 10;
++ return std::chrono::duration_cast<std::chrono::microseconds>(
++ std::chrono::seconds(*timeoutValue + timeoutMarginSeconds))
++ .count();
++ }
++ else
++ {
++ return std::nullopt;
++ }
++}
++
+ /**
+ * @brief Fill template for Virtual Media Item.
+ */
+@@ -856,22 +878,54 @@ class VirtualMediaActionInsertMedia : public Node
+ }
+
+ crow::connections::systemBus->async_method_call(
+- [asyncResp, secretPipe](const boost::system::error_code ec,
+- bool success) {
++ [asyncResp, service, name, imageUrl, rw, unixFd,
++ secretPipe](const boost::system::error_code ec,
++ const std::variant<int> timeoutProperty) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
+ messages::internalError(asyncResp->res);
++ return;
+ }
+- else if (!success)
++
++ auto timeout = vmParseTimeoutProperty(timeoutProperty);
++ if (timeout == std::nullopt)
+ {
+- BMCWEB_LOG_ERROR << "Service responded with error";
+- messages::generalError(asyncResp->res);
++ BMCWEB_LOG_ERROR << "Timeout property is empty.";
++ messages::internalError(asyncResp->res);
++ return;
+ }
++
++ crow::connections::systemBus->async_method_call_timed(
++ [asyncResp, secretPipe](const boost::system::error_code ec,
++ bool success) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Bad D-Bus request error: "
++ << ec;
++ if (ec ==
++ boost::system::errc::device_or_resource_busy)
++ {
++ messages::resourceInUse(asyncResp->res);
++ }
++ else
++ {
++ messages::internalError(asyncResp->res);
++ }
++ }
++ else if (!success)
++ {
++ BMCWEB_LOG_ERROR << "Service responded with error";
++ messages::generalError(asyncResp->res);
++ }
++ },
++ service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
++ "xyz.openbmc_project.VirtualMedia.Legacy", "Mount",
++ *timeout, imageUrl, rw, unixFd);
+ },
+ service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
+- "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
+- unixFd);
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.VirtualMedia.MountPoint", "Timeout");
+ }
+ };
+
+@@ -1003,38 +1057,60 @@ class VirtualMediaActionEjectMedia : public Node
+ const std::string& service, const std::string& name,
+ bool legacy)
+ {
+-
+- // Legacy mount requires parameter with image
++ std::string objectPath = "/xyz/openbmc_project/VirtualMedia/";
++ std::string ifaceName = "xyz.openbmc_project.VirtualMedia";
+ if (legacy)
+ {
+- crow::connections::systemBus->async_method_call(
+- [asyncResp](const boost::system::error_code ec) {
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
+-
+- messages::internalError(asyncResp->res);
+- return;
+- }
+- },
+- service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
+- "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
++ objectPath += "Legacy/";
++ ifaceName += ".Legacy";
+ }
+- else // proxy
++ else
+ {
+- crow::connections::systemBus->async_method_call(
+- [asyncResp](const boost::system::error_code ec) {
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
+-
+- messages::internalError(asyncResp->res);
+- return;
+- }
+- },
+- service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
+- "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
++ objectPath += "Proxy/";
++ ifaceName += ".Proxy";
+ }
++ objectPath += name;
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp, service, name, objectPath,
++ ifaceName](const boost::system::error_code ec,
++ const std::variant<int> timeoutProperty) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ auto timeout = vmParseTimeoutProperty(timeoutProperty);
++ if (timeout == std::nullopt)
++ {
++ BMCWEB_LOG_ERROR << "Timeout property is empty.";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ crow::connections::systemBus->async_method_call_timed(
++ [asyncResp](const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Bad D-Bus request error: "
++ << ec;
++ if (ec ==
++ boost::system::errc::device_or_resource_busy)
++ {
++ messages::resourceInUse(asyncResp->res);
++ }
++ else
++ {
++ messages::internalError(asyncResp->res);
++ }
++ return;
++ }
++ },
++ service, objectPath, ifaceName, "Unmount", *timeout);
++ },
++ service, objectPath, "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.VirtualMedia.MountPoint", "Timeout");
+ }
+ };
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0003-Add-ConnectedVia-property-to-virtual-media-item-temp.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0003-Add-ConnectedVia-property-to-virtual-media-item-temp.patch
new file mode 100644
index 000000000..41c1c9836
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0003-Add-ConnectedVia-property-to-virtual-media-item-temp.patch
@@ -0,0 +1,28 @@
+From d303bfdd6778c43096401ff78fab70f9041cd4cf Mon Sep 17 00:00:00 2001
+From: Karol Wachowski <karol.wachowski@intel.com>
+Date: Thu, 11 Feb 2021 08:35:41 +0000
+Subject: [PATCH] Add ConnectedVia property to virtual media item template
+
+Tested: Verified that ConnectedVia property is returned and set to
+ "NotConnected" for disconnected media.
+
+Signed-off-by: Karol Wachowski <karol.wachowski@intel.com>
+---
+ redfish-core/lib/virtual_media.hpp | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp
+index c45fed2..aa7c639 100644
+--- a/redfish-core/lib/virtual_media.hpp
++++ b/redfish-core/lib/virtual_media.hpp
+@@ -193,6 +193,7 @@ static nlohmann::json vmItemTemplate(const std::string& name,
+ item["@odata.id"] =
+ "/redfish/v1/Managers/" + name + "/VirtualMedia/" + resName;
+ item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
++ item["ConnectedVia"] = "NotConnected";
+ item["Name"] = "Virtual Removable Media";
+ item["Id"] = resName;
+ item["WriteProtected"] = true;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0004-Invalid-status-code-from-InsertMedia-REST-methods.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0004-Invalid-status-code-from-InsertMedia-REST-methods.patch
new file mode 100644
index 000000000..3a9e67217
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0004-Invalid-status-code-from-InsertMedia-REST-methods.patch
@@ -0,0 +1,185 @@
+From 805641a2d189da9befc05168f51cef76da1ba326 Mon Sep 17 00:00:00 2001
+From: Alicja Rybak <alicja.rybak@intel.com>
+Date: Tue, 20 Apr 2021 16:32:37 +0200
+Subject: [PATCH] Invalid status code from InsertMedia REST methods GET,
+ PUT, DELETE, PATCH in proxy mode
+
+Add handlers for GET, PUT, DELETE, PATCH method and function that
+checks which mode is used and set suitable status code:
+Not allowed for Legacy and Not found for Proxy.
+
+Change-Id: Ib4c0a3e9a2a8853caa74c59239d9fcfed99c5e8b
+Signed-off-by: Alicja Rybak <alicja.rybak@intel.com>
+---
+ redfish-core/lib/virtual_media.hpp | 155 +++++++++++++++++++++++++++++
+ 1 file changed, 155 insertions(+)
+
+diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp
+index aa7c639..3e28164 100644
+--- a/redfish-core/lib/virtual_media.hpp
++++ b/redfish-core/lib/virtual_media.hpp
+@@ -548,6 +548,161 @@ class VirtualMediaActionInsertMedia : public Node
+ return true;
+ }
+
++ /**
++ * @brief Function checks if insert media request is Legacy or Proxy type
++ * and sets suitable response code for unsupported REST method.
++ *
++ */
++ void CheckProxyMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
++ const crow::Request& req,
++ const std::vector<std::string>& params)
++ {
++ if (params.size() != 2)
++ {
++ messages::internalError(aResp->res);
++ return;
++ }
++
++ // take resource name from URL
++ const std::string& resName = params[1];
++
++ if (params[0] != "bmc")
++ {
++ messages::resourceNotFound(aResp->res, "VirtualMedia.Insert",
++ resName);
++
++ return;
++ }
++
++ crow::connections::systemBus->async_method_call(
++ [this, aResp{std::move(aResp)}, req,
++ resName](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
++ << ec;
++ aResp->res.result(boost::beast::http::status::not_found);
++
++ return;
++ }
++ std::string service = getObjectType.begin()->first;
++ BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
++
++ crow::connections::systemBus->async_method_call(
++ [this, service, resName, req,
++ aResp{aResp}](const boost::system::error_code ec,
++ ManagedObjectType& subtree) {
++ if (ec)
++ {
++ BMCWEB_LOG_DEBUG << "DBUS response error";
++
++ return;
++ }
++
++ for (auto& item : subtree)
++ {
++ std::string thispath = item.first.filename();
++ if (thispath.empty())
++ {
++ continue;
++ }
++
++ if (thispath != resName)
++ {
++ continue;
++ }
++
++ auto mode = item.first.parent_path();
++ auto type = mode.parent_path();
++ if (mode.filename().empty() ||
++ type.filename().empty())
++ {
++ continue;
++ }
++
++ if (type.filename() != "VirtualMedia")
++ {
++ continue;
++ }
++
++ // Check if dbus path is Legacy type
++ if (mode.filename() == "Legacy")
++ {
++ BMCWEB_LOG_DEBUG << "InsertMedia only allowed "
++ "with POST method "
++ "in legacy mode";
++ aResp->res.result(boost::beast::http::status::
++ method_not_allowed);
++
++ return;
++ }
++ // Check if dbus path is Proxy type
++ if (mode.filename() == "Proxy")
++ {
++ // Not possible in proxy mode
++ BMCWEB_LOG_DEBUG << "InsertMedia not "
++ "allowed in proxy mode";
++ aResp->res.result(
++ boost::beast::http::status::not_found);
++
++ return;
++ }
++ }
++
++ BMCWEB_LOG_DEBUG << "Parent item not found";
++ aResp->res.result(
++ boost::beast::http::status::not_found);
++ },
++ service, "/xyz/openbmc_project/VirtualMedia",
++ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
++ }
++
++ /**
++ * @brief Function handles GET method request.
++ */
++ void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const crow::Request& req,
++ const std::vector<std::string>& params) override
++ {
++ CheckProxyMode(asyncResp, req, params);
++ }
++
++ /**
++ * @brief Function handles PATCH method request.
++ */
++ void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const crow::Request& req,
++ const std::vector<std::string>& params) override
++ {
++ CheckProxyMode(asyncResp, req, params);
++ }
++
++ /**
++ * @brief Function handles PUT method request.
++ */
++ void doPut(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const crow::Request& req,
++ const std::vector<std::string>& params) override
++ {
++ CheckProxyMode(asyncResp, req, params);
++ }
++
++ /**
++ * @brief Function handles DELETE method request.
++ */
++ void doDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const crow::Request& req,
++ const std::vector<std::string>& params) override
++ {
++ CheckProxyMode(asyncResp, req, params);
++ }
++
+ /**
+ * @brief Function handles POST method request.
+ *
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0005-Set-Inserted-redfish-property-for-not-inserted-resou.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0005-Set-Inserted-redfish-property-for-not-inserted-resou.patch
new file mode 100644
index 000000000..3d80aeb20
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0005-Set-Inserted-redfish-property-for-not-inserted-resou.patch
@@ -0,0 +1,43 @@
+From 89ca38dbc3433b3b734a20068e599809f3bd7b90 Mon Sep 17 00:00:00 2001
+From: Karol Wachowski <karol.wachowski@intel.com>
+Date: Tue, 23 Feb 2021 15:53:16 +0000
+Subject: [PATCH] Set Inserted redfish property for not inserted resources
+
+Tested: Verified that Inserted property is returned and set to
+ "false" for not inserted media.
+Signed-off-by: Karol Wachowski <karol.wachowski@intel.com>
+---
+ redfish-core/lib/virtual_media.hpp | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp
+index 3e28164..4c475b7 100644
+--- a/redfish-core/lib/virtual_media.hpp
++++ b/redfish-core/lib/virtual_media.hpp
+@@ -96,6 +96,7 @@ static void
+ BMCWEB_LOG_DEBUG << "Value Active not found";
+ return;
+ }
++ aResp->res.jsonValue["Inserted"] = *activeValue;
+
+ const std::string* endpointIdValue =
+ std::get_if<std::string>(&endpointIdProperty->second);
+@@ -107,7 +108,6 @@ static void
+ aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
+ *endpointIdValue;
+ aResp->res.jsonValue["TransferProtocolType"] = "OEM";
+- aResp->res.jsonValue["Inserted"] = *activeValue;
+ if (*activeValue == true)
+ {
+ aResp->res.jsonValue["ConnectedVia"] = "Applet";
+@@ -138,7 +138,6 @@ static void
+ }
+
+ aResp->res.jsonValue["Image"] = *imageUrlValue;
+- aResp->res.jsonValue["Inserted"] = *activeValue;
+ aResp->res.jsonValue["TransferProtocolType"] =
+ getTransferProtocolTypeFromUri(*imageUrlValue);
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0006-Bmcweb-handle-permission-denied-exception.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0006-Bmcweb-handle-permission-denied-exception.patch
new file mode 100644
index 000000000..efce3e72c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0006-Bmcweb-handle-permission-denied-exception.patch
@@ -0,0 +1,47 @@
+From e7018ea9e3ad1a17e096aec3717a4764c3feac2e Mon Sep 17 00:00:00 2001
+From: Alicja Rybak <alicja.rybak@intel.com>
+Date: Wed, 14 Apr 2021 16:26:59 +0200
+Subject: [PATCH] Bmcweb handle permission denied exception
+
+Add handling of permission denied exception (EPERM) that
+can be thrown by VirtualMedia service during Mount/Unmount dbus operations.
+
+Tested:
+Verified that after mounting/unmounting HTTPS resource twice in a row in legacy mode,
+VirtualMedia returns EPERM, which bmcweb handles as 403 status code.
+
+Change-Id: Ibc18d5ec822c5072605b1fc4651389982002798b
+Signed-off-by: Alicja Rybak <alicja.rybak@intel.com>
+---
+ redfish-core/lib/virtual_media.hpp | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp
+index 4c475b7..8151ac0 100644
+--- a/redfish-core/lib/virtual_media.hpp
++++ b/redfish-core/lib/virtual_media.hpp
+@@ -1073,6 +1073,10 @@ class VirtualMediaActionInsertMedia : public Node
+ {
+ messages::resourceInUse(asyncResp->res);
+ }
++ else if (ec == boost::system::errc::permission_denied)
++ {
++ messages::accessDenied(asyncResp->res, "VirtualMedia.Insert");
++ }
+ else
+ {
+ messages::internalError(asyncResp->res);
+@@ -1267,6 +1271,10 @@ class VirtualMediaActionEjectMedia : public Node
+ {
+ messages::resourceInUse(asyncResp->res);
+ }
++ else if (ec == boost::system::errc::permission_denied)
++ {
++ messages::accessDenied(asyncResp->res, "VirtualMedia.Eject");
++ }
+ else
+ {
+ messages::internalError(asyncResp->res);
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0007-Fix-unmounting-image-in-proxy-mode.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0007-Fix-unmounting-image-in-proxy-mode.patch
new file mode 100644
index 000000000..88fa89465
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0007-Fix-unmounting-image-in-proxy-mode.patch
@@ -0,0 +1,35 @@
+From 6f4b5fc1879f39b0f5fee0838f0ecbc481275d5e Mon Sep 17 00:00:00 2001
+From: Alicja Rybak <alicja.rybak@intel.com>
+Date: Fri, 23 Apr 2021 17:35:52 +0200
+Subject: [PATCH] Fix unmounting image in proxy mode.
+
+Sometimes Slot0 got higher key than Slot1 and erase function for Slot1
+invalidates elements with keys not less than the erased element.
+In that case invalid slot0 will be unmounted.
+Change order of calling close() and erase() functions to
+unmount correct device.
+
+Change-Id: I7a40a4518982f697d3eed635cde6d06978149cf0
+Signed-off-by: Alicja Rybak <alicja.rybak@intel.com>
+---
+ include/nbd_proxy.hpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/nbd_proxy.hpp b/include/nbd_proxy.hpp
+index 3b28823..897bcf2 100644
+--- a/include/nbd_proxy.hpp
++++ b/include/nbd_proxy.hpp
+@@ -439,9 +439,9 @@ inline void requestRoutes(App& app)
+ BMCWEB_LOG_DEBUG << "No session to close";
+ return;
+ }
++ session->second->close();
+ // Remove reference to session in global map
+ sessions.erase(session);
+- session->second->close();
+ })
+ .onmessage([](crow::websocket::Connection& conn,
+ const std::string& data, bool) {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0008-Fix-VM-NBDPROXY-build-issue-with-AsyncResp.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0008-Fix-VM-NBDPROXY-build-issue-with-AsyncResp.patch
new file mode 100644
index 000000000..c188b2105
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/vm/0008-Fix-VM-NBDPROXY-build-issue-with-AsyncResp.patch
@@ -0,0 +1,37 @@
+From d31d913a8c5dbacf6a36407532cf777852099ced Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Sun, 2 May 2021 11:07:16 +0000
+Subject: [PATCH] Fix VM NBDPROXY build issue with AsyncResp
+
+8d1b46d7 moves bmcweb to using AsyncResp everywhere, and not have
+each individual handler creating its own object.
+
+This commit fixes the build failure when enabling virtual media
+compile flag(BMCWEB_ENABLE_VM_NBDPROXY). This is caused by above
+mentioned recent change.
+
+Tested:
+ - Build is successful with enabled virtual media flag.
+
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Change-Id: I363a41a08fae9dc05b3553695b96ffd26948f696
+---
+ redfish-core/lib/virtual_media.hpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp
+index 685ee5c..99542c4 100644
+--- a/redfish-core/lib/virtual_media.hpp
++++ b/redfish-core/lib/virtual_media.hpp
+@@ -635,7 +635,7 @@ class VirtualMediaActionInsertMedia : public Node
+ }
+
+ bool paramsValid = validateParams(
+- asyncResp->res, imageUrl, inserted,
++ asyncResp, imageUrl, inserted,
+ transferMethod, transferProtocolType);
+
+ if (paramsValid == false)
+--
+2.17.1
+