| #include "command_table.hpp" | 
 |  | 
 | #include "main.hpp" | 
 | #include "message_handler.hpp" | 
 | #include "message_parsers.hpp" | 
 | #include "sessions_manager.hpp" | 
 |  | 
 | #include <ipmid/types.hpp> | 
 | #include <main.hpp> | 
 | #include <phosphor-logging/lg2.hpp> | 
 | #include <user_channel/user_layer.hpp> | 
 |  | 
 | #include <iomanip> | 
 |  | 
 | namespace command | 
 | { | 
 |  | 
 | void Table::registerCommand(CommandID inCommand, std::unique_ptr<Entry>&& 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<uint8_t>& commandData, | 
 |                            std::shared_ptr<message::Handler> 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> session = | 
 |             session::Manager::get().getSession(handler->sessionID); | 
 |  | 
 |         // Ignore messages that are not part of an active session | 
 |         auto state = static_cast<session::State>(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, uint8_t, uint8_t, uint8_t, | 
 |                                            std::vector<uint8_t>>; | 
 |         uint8_t lun = command.lun(); | 
 |         uint8_t netFn = command.netFn(); | 
 |         uint8_t cmd = command.cmd(); | 
 |  | 
 |         std::map<std::string, ipmi::Value> options = { | 
 |             {"userId", ipmi::Value(static_cast<int>( | 
 |                            ipmi::ipmiUserGetUserId(session->userName)))}, | 
 |             {"privilege", | 
 |              ipmi::Value(static_cast<int>(session->currentPrivilege()))}, | 
 |             {"currentSessionId", | 
 |              ipmi::Value(static_cast<uint32_t>(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<uint8_t>& responseData = | 
 |                     std::get<4>(response); | 
 |                 std::vector<uint8_t> 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<uint8_t> 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> session = | 
 |                 session::Manager::get().getSession(handler->sessionID); | 
 |             auto state = static_cast<session::State>(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<size_t> elapsedSeconds = | 
 |             std::chrono::duration_cast<std::chrono::seconds>(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<uint8_t> | 
 |     NetIpmidEntry::executeCommand(std::vector<uint8_t>& commandData, | 
 |                                   std::shared_ptr<message::Handler> handler) | 
 | { | 
 |     std::vector<uint8_t> 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 |