1 #include "command_table.hpp" 2 3 #include "message_handler.hpp" 4 #include "message_parsers.hpp" 5 #include "sessions_manager.hpp" 6 #include "xyz/openbmc_project/Common/error.hpp" 7 8 #include <iomanip> 9 #include <iostream> 10 #include <phosphor-logging/elog-errors.hpp> 11 #include <phosphor-logging/log.hpp> 12 13 using namespace phosphor::logging; 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 log<level::DEBUG>( 25 "Already Registered", 26 phosphor::logging::entry("SKIPPED_ENTRY=0x%x", 27 uint32_t(inCommand.command))); 28 return; 29 } 30 31 command = std::move(entry); 32 } 33 34 std::vector<uint8_t> Table::executeCommand(uint32_t inCommand, 35 std::vector<uint8_t>& commandData, 36 const message::Handler& handler) 37 { 38 using namespace std::chrono_literals; 39 40 std::vector<uint8_t> response; 41 42 auto iterator = commandTable.find(inCommand); 43 44 if (iterator == commandTable.end()) 45 { 46 response.resize(1); 47 response[0] = IPMI_CC_INVALID; 48 } 49 else 50 { 51 auto start = std::chrono::steady_clock::now(); 52 53 response = iterator->second->executeCommand(commandData, handler); 54 55 auto end = std::chrono::steady_clock::now(); 56 57 auto elapsedSeconds = 58 std::chrono::duration_cast<std::chrono::seconds>(end - start); 59 60 // If command time execution time exceeds 2 seconds, log a time 61 // exceeded message 62 if (elapsedSeconds > 2s) 63 { 64 std::cerr << "E> IPMI command timed out:Elapsed time = " 65 << elapsedSeconds.count() << "s" 66 << "\n"; 67 } 68 } 69 return response; 70 } 71 72 std::vector<uint8_t> 73 NetIpmidEntry::executeCommand(std::vector<uint8_t>& commandData, 74 const message::Handler& handler) 75 { 76 std::vector<uint8_t> errResponse; 77 78 // Check if the command qualifies to be run prior to establishing a session 79 if (!sessionless && (handler.sessionID == session::SESSION_ZERO)) 80 { 81 errResponse.resize(1); 82 errResponse[0] = IPMI_CC_INSUFFICIENT_PRIVILEGE; 83 std::cerr << "E> Table::Not enough privileges for command 0x" 84 << std::hex << command.command << "\n"; 85 return errResponse; 86 } 87 88 return functor(commandData, handler); 89 } 90 91 std::vector<uint8_t> 92 ProviderIpmidEntry::executeCommand(std::vector<uint8_t>& commandData, 93 const message::Handler& handler) 94 { 95 std::vector<uint8_t> response(message::parser::MAX_PAYLOAD_SIZE - 1); 96 size_t respSize = commandData.size(); 97 ipmi_ret_t ipmiRC = IPMI_CC_UNSPECIFIED_ERROR; 98 try 99 { 100 ipmiRC = functor(0, 0, reinterpret_cast<void*>(commandData.data()), 101 reinterpret_cast<void*>(response.data() + 1), 102 &respSize, NULL); 103 } 104 // IPMI command handlers can throw unhandled exceptions, catch those 105 // and return sane error code. 106 catch (const std::exception& e) 107 { 108 std::cerr << "E> Unspecified error for command 0x" << std::hex 109 << command.command << " - " << e.what() << "\n"; 110 respSize = 0; 111 // fall through 112 } 113 /* 114 * respSize gets you the size of the response data for the IPMI command. The 115 * first byte in a response to the IPMI command is the Completion Code. 116 * So we are inserting completion code as the first byte and incrementing 117 * the response payload size by the size of the completion code. 118 */ 119 response[0] = ipmiRC; 120 response.resize(respSize + sizeof(ipmi_ret_t)); 121 122 return response; 123 } 124 125 } // namespace command 126