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