#include "command_table.hpp" #include "main.hpp" #include "message_handler.hpp" #include "message_parsers.hpp" #include "sessions_manager.hpp" #include #include #include #include using namespace phosphor::logging; 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", uint32_t(inCommand.command))); return; } command = std::move(entry); } std::vector Table::executeCommand(uint32_t inCommand, std::vector& commandData, const message::Handler& handler) { using namespace std::chrono_literals; std::vector response; auto iterator = commandTable.find(inCommand); if (iterator == commandTable.end()) { response.resize(1); response[0] = IPMI_CC_INVALID; } else { auto start = std::chrono::steady_clock::now(); response = 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())); } } return response; } std::vector NetIpmidEntry::executeCommand(std::vector& commandData, const message::Handler& 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", int(command.NetFnLun.lun)), entry("NETFN=%x", int(command.NetFnLun.netFn)), entry("CMD=%x", command.cmd)); return errResponse; } return functor(commandData, handler); } std::vector ProviderIpmidEntry::executeCommand(std::vector& commandData, const message::Handler& handler) { std::vector response(message::parser::MAX_PAYLOAD_SIZE - 1); size_t respSize = commandData.size(); ipmi_ret_t ipmiRC = IPMI_CC_UNSPECIFIED_ERROR; std::shared_ptr session = std::get(singletonPool) .getSession(handler.sessionID); if (session->curPrivLevel >= Entry::getPrivilege()) { try { ipmiRC = functor(0, 0, reinterpret_cast(commandData.data()), reinterpret_cast(response.data() + 1), &respSize, NULL); } // IPMI command handlers can throw unhandled exceptions, catch those // and return sane error code. catch (const std::exception& e) { log("Table: Unspecified error for command", entry("EXCEPTION=%s", e.what()), entry("LUN=%x", int(command.NetFnLun.lun)), entry("NETFN=%x", int(command.NetFnLun.netFn)), entry("CMD=%x", command.cmd)); respSize = 0; // fall through } } else { respSize = 0; ipmiRC = IPMI_CC_INSUFFICIENT_PRIVILEGE; } /* * respSize gets you the size of the response data for the IPMI command. The * first byte in a response to the IPMI command is the Completion Code. * So we are inserting completion code as the first byte and incrementing * the response payload size by the size of the completion code. */ response[0] = ipmiRC; response.resize(respSize + sizeof(ipmi_ret_t)); return response; } } // namespace command