#include "command_table.hpp" #include "main.hpp" #include "message_handler.hpp" #include "message_parsers.hpp" #include "sessions_manager.hpp" #include #include #include #include #include #include using namespace sdbusplus::xyz::openbmc_project::Common::Error; using namespace phosphor::logging; namespace ipmi { using Value = sdbusplus::message::variant; } // namespace ipmi namespace command { void Table::registerCommand(CommandID inCommand, std::unique_ptr&& entry) { auto& command = commandTable[inCommand.command]; if (command) { log( "Already Registered", phosphor::logging::entry("SKIPPED_ENTRY=0x%x", inCommand.command)); return; } command = std::move(entry); } void Table::executeCommand(uint32_t inCommand, std::vector& commandData, std::shared_ptr handler) { using namespace std::chrono_literals; auto iterator = commandTable.find(inCommand); if (iterator == commandTable.end()) { CommandID command(inCommand); auto bus = getSdBus(); // forward the request onto the main ipmi queue using IpmiDbusRspType = std::tuple>; uint8_t lun = command.lun(); uint8_t netFn = command.netFn(); uint8_t cmd = command.cmd(); std::shared_ptr session = std::get(singletonPool) .getSession(handler->sessionID); std::map options = { {"userId", ipmi::Value(ipmi::ipmiUserGetUserId(session->userName))}, {"privilege", ipmi::Value(static_cast(session->curPrivLevel))}, }; bus->async_method_call( [handler, this](const boost::system::error_code& ec, const IpmiDbusRspType& response) { if (!ec) { const uint8_t& cc = std::get<3>(response); const std::vector& responseData = std::get<4>(response); std::vector payload; payload.reserve(1 + responseData.size()); payload.push_back(cc); payload.insert(payload.end(), responseData.begin(), responseData.end()); handler->outPayload = std::move(payload); } else { std::vector payload; payload.push_back(IPMI_CC_UNSPECIFIED_ERROR); handler->outPayload = std::move(payload); } }, "xyz.openbmc_project.Ipmi.Host", "/xyz/openbmc_project/Ipmi", "xyz.openbmc_project.Ipmi.Server", "execute", netFn, lun, cmd, commandData, options); } else { auto start = std::chrono::steady_clock::now(); handler->outPayload = iterator->second->executeCommand(commandData, handler); auto end = std::chrono::steady_clock::now(); auto elapsedSeconds = std::chrono::duration_cast(end - start); // If command time execution time exceeds 2 seconds, log a time // exceeded message if (elapsedSeconds > 2s) { log("IPMI command timed out", entry("DELAY=%d", elapsedSeconds.count())); } } } std::vector NetIpmidEntry::executeCommand(std::vector& commandData, std::shared_ptr handler) { std::vector errResponse; // Check if the command qualifies to be run prior to establishing a session if (!sessionless && (handler->sessionID == session::SESSION_ZERO)) { errResponse.resize(1); errResponse[0] = IPMI_CC_INSUFFICIENT_PRIVILEGE; log("Table: Insufficient privilege for command", entry("LUN=%x", command.lun()), entry("NETFN=%x", command.netFn()), entry("CMD=%x", command.cmd())); return errResponse; } return functor(commandData, *handler); } } // namespace command