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