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