#pragma once #include "app.hpp" #include "async_resp.hpp" #include "dbus_utility.hpp" #include "error_messages.hpp" #include "utils/collection.hpp" #include "utils/hex_utils.hpp" #include "utils/json_utils.hpp" #include #include #include #include namespace crow { namespace google_api { inline void handleGoogleV1Get(const crow::Request& /*req*/, const std::shared_ptr& asyncResp) { asyncResp->res.jsonValue["@odata.type"] = "#GoogleServiceRoot.v1_0_0.GoogleServiceRoot"; asyncResp->res.jsonValue["@odata.id"] = "/google/v1"; asyncResp->res.jsonValue["Id"] = "Google Rest RootService"; asyncResp->res.jsonValue["Name"] = "Google Service Root"; asyncResp->res.jsonValue["Version"] = "1.0.0"; asyncResp->res.jsonValue["RootOfTrustCollection"]["@odata.id"] = "/google/v1/RootOfTrustCollection"; } inline void handleRootOfTrustCollectionGet( const crow::Request& /*req*/, const std::shared_ptr& asyncResp) { asyncResp->res.jsonValue["@odata.id"] = "/google/v1/RootOfTrustCollection"; asyncResp->res.jsonValue["@odata.type"] = "#RootOfTrustCollection.RootOfTrustCollection"; const std::array interfaces{ "xyz.openbmc_project.Control.Hoth"}; redfish::collection_util::getCollectionMembers( asyncResp, boost::urls::url("/google/v1/RootOfTrustCollection"), interfaces, "/xyz/openbmc_project"); } // Helper struct to identify a resolved D-Bus object interface struct ResolvedEntity { std::string id; std::string service; std::string object; std::string interface; }; using ResolvedEntityHandler = std::function&, const ResolvedEntity&)>; inline void hothGetSubtreeCallback( const std::string& command, const std::shared_ptr& asyncResp, const std::string& rotId, const ResolvedEntityHandler& entityHandler, const boost::system::error_code ec, const dbus::utility::MapperGetSubTreeResponse& subtree) { if (ec) { redfish::messages::internalError(asyncResp->res); return; } for (const auto& [path, services] : subtree) { sdbusplus::message::object_path objPath(path); if (objPath.filename() != rotId || services.empty()) { continue; } ResolvedEntity resolvedEntity = { .id = rotId, .service = services[0].first, .object = path, .interface = "xyz.openbmc_project.Control.Hoth"}; entityHandler(command, asyncResp, resolvedEntity); return; } // Couldn't find an object with that name. return an error redfish::messages::resourceNotFound(asyncResp->res, "RootOfTrust", rotId); } inline void resolveRoT(const std::string& command, const std::shared_ptr& asyncResp, const std::string& rotId, ResolvedEntityHandler&& entityHandler) { constexpr std::array hothIfaces = { "xyz.openbmc_project.Control.Hoth"}; crow::connections::systemBus->async_method_call( [command, asyncResp, rotId, entityHandler{std::forward(entityHandler)}]( const boost::system::error_code ec, const dbus::utility::MapperGetSubTreeResponse& subtree) { hothGetSubtreeCallback(command, asyncResp, rotId, entityHandler, ec, subtree); }, "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper", "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/xyz/openbmc_project", /*depth=*/0, hothIfaces); } inline void populateRootOfTrustEntity( const std::string& /*unused*/, const std::shared_ptr& asyncResp, const ResolvedEntity& resolvedEntity) { asyncResp->res.jsonValue["@odata.type"] = "#RootOfTrust.v1_0_0.RootOfTrust"; asyncResp->res.jsonValue["@odata.id"] = "/google/v1/RootOfTrustCollection/" + resolvedEntity.id; asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; asyncResp->res.jsonValue["Id"] = resolvedEntity.id; // Need to fix this later to a stabler property. asyncResp->res.jsonValue["Name"] = resolvedEntity.id; asyncResp->res.jsonValue["Description"] = "Google Root Of Trust"; asyncResp->res.jsonValue["Actions"]["#RootOfTrust.SendCommand"]["target"] = "/google/v1/RootOfTrustCollection/" + resolvedEntity.id + "/Actions/RootOfTrust.SendCommand"; asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] = resolvedEntity.id; asyncResp->res.jsonValue["Location"]["PartLocation"]["LocationType"] = "Embedded"; } inline void handleRootOfTrustGet(const crow::Request& /*req*/, const std::shared_ptr& asyncResp, const std::string& param) { std::string emptyCommand; resolveRoT(emptyCommand, asyncResp, param, populateRootOfTrustEntity); } inline void invocationCallback(const std::shared_ptr& asyncResp, const boost::system::error_code ec, const std::vector& responseBytes) { if (ec) { BMCWEB_LOG_ERROR << "RootOfTrust.Actions.SendCommand failed: " << ec.message(); redfish::messages::internalError(asyncResp->res); return; } asyncResp->res.jsonValue["CommandResponse"] = bytesToHexString(responseBytes); } inline void invokeRoTCommand(const std::string& command, const std::shared_ptr& asyncResp, const ResolvedEntity& resolvedEntity) { std::vector bytes = hexStringToBytes(command); if (bytes.empty()) { BMCWEB_LOG_DEBUG << "Invalid command: " << command; redfish::messages::actionParameterValueTypeError(command, "Command", "SendCommand"); return; } crow::connections::systemBus->async_method_call( [asyncResp{asyncResp}](const boost::system::error_code ec, const std::vector& responseBytes) { invocationCallback(asyncResp, ec, responseBytes); }, resolvedEntity.service, resolvedEntity.object, resolvedEntity.interface, "SendHostCommand", bytes); } inline void handleRoTSendCommandPost( const crow::Request& request, const std::shared_ptr& asyncResp, const std::string& rotId) { std::string command; if (!redfish::json_util::readJsonAction(request, asyncResp->res, "Command", command)) { BMCWEB_LOG_DEBUG << "Missing property Command."; redfish::messages::actionParameterMissing(asyncResp->res, "SendCommand", "Command"); return; } resolveRoT(command, asyncResp, rotId, invokeRoTCommand); } inline void requestRoutes(App& app) { BMCWEB_ROUTE(app, "/google/v1/") .methods(boost::beast::http::verb::get)(handleGoogleV1Get); BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection") .privileges({{"ConfigureManager"}}) .methods(boost::beast::http::verb::get)(handleRootOfTrustCollectionGet); BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection/") .privileges({{"ConfigureManager"}}) .methods(boost::beast::http::verb::get)(handleRootOfTrustGet); BMCWEB_ROUTE( app, "/google/v1/RootOfTrustCollection//Actions/RootOfTrust.SendCommand") .privileges({{"ConfigureManager"}}) .methods(boost::beast::http::verb::post)(handleRoTSendCommandPost); } } // namespace google_api } // namespace crow