#include "command_table.hpp" #include "main.hpp" #include "message_handler.hpp" #include "message_parsers.hpp" #include "sessions_manager.hpp" #include #include #include #include #include namespace command { void Table::registerCommand(CommandID inCommand, std::unique_ptr&& entry) { auto& command = commandTable[inCommand.command]; if (command) { lg2::debug("Already Registered: {COMMAND}", "COMMAND", 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); // Do not forward any session zero commands to ipmid if (handler->sessionID == session::sessionZero) { lg2::info( "Table: refuse to forward session-zero command: lun: {LUN}, netFn: {NETFN}, command: {COMMAND}", "LUN", command.lun(), "NETFN", command.netFn(), "COMMAND", command.cmd()); return; } std::shared_ptr session = session::Manager::get().getSession(handler->sessionID); // Ignore messages that are not part of an active session auto state = static_cast(session->state()); if (state != session::State::active) { return; } 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::map options = { {"userId", ipmi::Value(static_cast( ipmi::ipmiUserGetUserId(session->userName)))}, {"privilege", ipmi::Value(static_cast(session->currentPrivilege()))}, {"currentSessionId", ipmi::Value(static_cast(session->getBMCSessionID()))}, }; 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(); // Ignore messages that are not part of an active/pre-active session if (handler->sessionID != session::sessionZero) { std::shared_ptr session = session::Manager::get().getSession(handler->sessionID); auto state = static_cast(session->state()); if ((state != session::State::setupInProgress) && (state != session::State::active)) { return; } } handler->outPayload = iterator->second->executeCommand(commandData, handler); auto end = std::chrono::steady_clock::now(); std::chrono::duration elapsedSeconds = std::chrono::duration_cast(end - start); // If command time execution time exceeds 2 seconds, log a time // exceeded message if (elapsedSeconds > 2s) { lg2::error("IPMI command timed out: {DELAY}", "DELAY", 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::sessionZero)) { errResponse.resize(1); errResponse[0] = IPMI_CC_INSUFFICIENT_PRIVILEGE; lg2::info( "Table: Insufficient privilege for command: lun: {LUN}, netFn: {NETFN}, command: {COMMAND}", "LUN", command.lun(), "NETFN", command.netFn(), "COMMAND", command.cmd()); return errResponse; } return functor(commandData, handler); } } // namespace command