1 #include "command_table.hpp" 2 3 #include "main.hpp" 4 #include "message_handler.hpp" 5 #include "message_parsers.hpp" 6 #include "sessions_manager.hpp" 7 8 #include <iomanip> 9 #include <main.hpp> 10 #include <phosphor-logging/elog-errors.hpp> 11 #include <phosphor-logging/log.hpp> 12 #include <user_channel/user_layer.hpp> 13 #include <xyz/openbmc_project/Common/error.hpp> 14 15 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 16 using namespace phosphor::logging; 17 18 namespace ipmi 19 { 20 using Value = std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t, 21 int64_t, uint64_t, double, std::string>; 22 23 } // namespace ipmi 24 25 namespace command 26 { 27 28 void Table::registerCommand(CommandID inCommand, std::unique_ptr<Entry>&& entry) 29 { 30 auto& command = commandTable[inCommand.command]; 31 32 if (command) 33 { 34 log<level::DEBUG>( 35 "Already Registered", 36 phosphor::logging::entry("SKIPPED_ENTRY=0x%x", inCommand.command)); 37 return; 38 } 39 40 command = std::move(entry); 41 } 42 43 void Table::executeCommand(uint32_t inCommand, 44 std::vector<uint8_t>& commandData, 45 std::shared_ptr<message::Handler> handler) 46 { 47 using namespace std::chrono_literals; 48 49 auto iterator = commandTable.find(inCommand); 50 51 if (iterator == commandTable.end()) 52 { 53 CommandID command(inCommand); 54 55 auto bus = getSdBus(); 56 // forward the request onto the main ipmi queue 57 using IpmiDbusRspType = std::tuple<uint8_t, uint8_t, uint8_t, uint8_t, 58 std::vector<uint8_t>>; 59 uint8_t lun = command.lun(); 60 uint8_t netFn = command.netFn(); 61 uint8_t cmd = command.cmd(); 62 std::shared_ptr<session::Session> session = 63 std::get<session::Manager&>(singletonPool) 64 .getSession(handler->sessionID); 65 std::map<std::string, ipmi::Value> options = { 66 {"userId", ipmi::Value(static_cast<int>( 67 ipmi::ipmiUserGetUserId(session->userName)))}, 68 {"privilege", 69 ipmi::Value(static_cast<int>(session->currentPrivilege()))}, 70 {"currentSessionId", 71 ipmi::Value(static_cast<uint32_t>(session->getBMCSessionID()))}, 72 }; 73 bus->async_method_call( 74 [handler, this](const boost::system::error_code& ec, 75 const IpmiDbusRspType& response) { 76 if (!ec) 77 { 78 const uint8_t& cc = std::get<3>(response); 79 const std::vector<uint8_t>& responseData = 80 std::get<4>(response); 81 std::vector<uint8_t> payload; 82 payload.reserve(1 + responseData.size()); 83 payload.push_back(cc); 84 payload.insert(payload.end(), responseData.begin(), 85 responseData.end()); 86 handler->outPayload = std::move(payload); 87 } 88 else 89 { 90 std::vector<uint8_t> payload; 91 payload.push_back(IPMI_CC_UNSPECIFIED_ERROR); 92 handler->outPayload = std::move(payload); 93 } 94 }, 95 "xyz.openbmc_project.Ipmi.Host", "/xyz/openbmc_project/Ipmi", 96 "xyz.openbmc_project.Ipmi.Server", "execute", netFn, lun, cmd, 97 commandData, options); 98 } 99 else 100 { 101 auto start = std::chrono::steady_clock::now(); 102 103 handler->outPayload = 104 iterator->second->executeCommand(commandData, handler); 105 106 auto end = std::chrono::steady_clock::now(); 107 108 std::chrono::duration<size_t> elapsedSeconds = 109 std::chrono::duration_cast<std::chrono::seconds>(end - start); 110 111 // If command time execution time exceeds 2 seconds, log a time 112 // exceeded message 113 if (elapsedSeconds > 2s) 114 { 115 log<level::ERR>("IPMI command timed out", 116 entry("DELAY=%zu", elapsedSeconds.count())); 117 } 118 } 119 } 120 121 std::vector<uint8_t> 122 NetIpmidEntry::executeCommand(std::vector<uint8_t>& commandData, 123 std::shared_ptr<message::Handler> handler) 124 { 125 std::vector<uint8_t> errResponse; 126 127 // Check if the command qualifies to be run prior to establishing a session 128 if (!sessionless && (handler->sessionID == session::sessionZero)) 129 { 130 errResponse.resize(1); 131 errResponse[0] = IPMI_CC_INSUFFICIENT_PRIVILEGE; 132 log<level::INFO>("Table: Insufficient privilege for command", 133 entry("LUN=%x", command.lun()), 134 entry("NETFN=%x", command.netFn()), 135 entry("CMD=%x", command.cmd())); 136 return errResponse; 137 } 138 139 return functor(commandData, *handler); 140 } 141 142 } // namespace command 143