blob: 90ff145589b1c627d7e2a40980126ca45bc60113 [file] [log] [blame]
Tom Joseph07181f52016-08-08 08:17:08 -05001#include "command_table.hpp"
2
Tom Joseph07181f52016-08-08 08:17:08 -05003#include "message_handler.hpp"
Tom Joseph1efcb492017-01-31 16:56:47 +05304#include "message_parsers.hpp"
Tom Joseph07181f52016-08-08 08:17:08 -05005#include "sessions_manager.hpp"
Nagaraju Goruganti1d9d4162018-03-22 01:27:37 -05006
Vernon Mauery9e801a22018-10-12 13:20:49 -07007#include <iomanip>
8#include <iostream>
9#include <phosphor-logging/elog-errors.hpp>
10#include <phosphor-logging/log.hpp>
Vernon Maueryf41a5542018-10-15 16:04:17 -070011#include <xyz/openbmc_project/Common/error.hpp>
Vernon Mauery9e801a22018-10-12 13:20:49 -070012
Nagaraju Goruganti1d9d4162018-03-22 01:27:37 -050013using namespace phosphor::logging;
Tom Joseph07181f52016-08-08 08:17:08 -050014
15namespace command
16{
17
18void Table::registerCommand(CommandID inCommand, std::unique_ptr<Entry>&& entry)
19{
Feist, Jamesbd45aae2017-10-26 15:06:13 -070020 auto& command = commandTable[inCommand.command];
21
22 if (command)
23 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070024 log<level::DEBUG>(
25 "Already Registered",
26 phosphor::logging::entry("SKIPPED_ENTRY=0x%x",
27 uint32_t(inCommand.command)));
Feist, Jamesbd45aae2017-10-26 15:06:13 -070028 return;
29 }
30
Feist, Jamesbd45aae2017-10-26 15:06:13 -070031 command = std::move(entry);
Tom Joseph07181f52016-08-08 08:17:08 -050032}
33
34std::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 {
Tom Joseph07181f52016-08-08 08:17:08 -050046 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
Vernon Mauery9e801a22018-10-12 13:20:49 -070057 auto elapsedSeconds =
58 std::chrono::duration_cast<std::chrono::seconds>(end - start);
Tom Joseph07181f52016-08-08 08:17:08 -050059
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 = "
Vernon Mauery9e801a22018-10-12 13:20:49 -070065 << elapsedSeconds.count() << "s"
66 << "\n";
Tom Joseph07181f52016-08-08 08:17:08 -050067 }
68 }
69 return response;
70}
71
Vernon Mauery9e801a22018-10-12 13:20:49 -070072std::vector<uint8_t>
73 NetIpmidEntry::executeCommand(std::vector<uint8_t>& commandData,
74 const message::Handler& handler)
Tom Joseph07181f52016-08-08 08:17:08 -050075{
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
Vernon Mauery9e801a22018-10-12 13:20:49 -070091std::vector<uint8_t>
92 ProviderIpmidEntry::executeCommand(std::vector<uint8_t>& commandData,
93 const message::Handler& handler)
Tom606e8cb2016-12-02 13:36:14 +053094{
Tom Joseph1efcb492017-01-31 16:56:47 +053095 std::vector<uint8_t> response(message::parser::MAX_PAYLOAD_SIZE - 1);
Feist, Jamesbd45aae2017-10-26 15:06:13 -070096 size_t respSize = commandData.size();
Richard Marian Thomaiyar1d82b222018-06-06 14:38:34 +053097 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 }
Tom606e8cb2016-12-02 13:36:14 +0530113 /*
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
Tom Joseph07181f52016-08-08 08:17:08 -0500125} // namespace command