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