blob: d0ef1736dcfc6ff0c7fcdc112bca21ad3536ff43 [file] [log] [blame]
Tom Joseph07181f52016-08-08 08:17:08 -05001#include "command_table.hpp"
2
Richard Marian Thomaiyar472a37b2018-09-06 07:11:07 +05303#include "main.hpp"
Tom Joseph07181f52016-08-08 08:17:08 -05004#include "message_handler.hpp"
Tom Joseph1efcb492017-01-31 16:56:47 +05305#include "message_parsers.hpp"
Tom Joseph07181f52016-08-08 08:17:08 -05006#include "sessions_manager.hpp"
Nagaraju Goruganti1d9d4162018-03-22 01:27:37 -05007
Vernon Mauery9e801a22018-10-12 13:20:49 -07008#include <iomanip>
Vernon Mauery9e801a22018-10-12 13:20:49 -07009#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 {
Vernon Maueryfc37e592018-12-19 14:55:15 -080064 log<level::ERR>("IPMI command timed out",
65 entry("DELAY=%d", elapsedSeconds.count()));
Tom Joseph07181f52016-08-08 08:17:08 -050066 }
67 }
68 return response;
69}
70
Vernon Mauery9e801a22018-10-12 13:20:49 -070071std::vector<uint8_t>
72 NetIpmidEntry::executeCommand(std::vector<uint8_t>& commandData,
73 const message::Handler& handler)
Tom Joseph07181f52016-08-08 08:17:08 -050074{
75 std::vector<uint8_t> errResponse;
76
77 // Check if the command qualifies to be run prior to establishing a session
78 if (!sessionless && (handler.sessionID == session::SESSION_ZERO))
79 {
80 errResponse.resize(1);
81 errResponse[0] = IPMI_CC_INSUFFICIENT_PRIVILEGE;
Vernon Maueryfc37e592018-12-19 14:55:15 -080082 log<level::INFO>("Table: Insufficient privilege for command",
83 entry("LUN=%x", int(command.NetFnLun.lun)),
84 entry("NETFN=%x", int(command.NetFnLun.netFn)),
85 entry("CMD=%x", command.cmd));
Tom Joseph07181f52016-08-08 08:17:08 -050086 return errResponse;
87 }
88
89 return functor(commandData, handler);
90}
91
Vernon Mauery9e801a22018-10-12 13:20:49 -070092std::vector<uint8_t>
93 ProviderIpmidEntry::executeCommand(std::vector<uint8_t>& commandData,
94 const message::Handler& handler)
Tom606e8cb2016-12-02 13:36:14 +053095{
Tom Joseph1efcb492017-01-31 16:56:47 +053096 std::vector<uint8_t> response(message::parser::MAX_PAYLOAD_SIZE - 1);
Feist, Jamesbd45aae2017-10-26 15:06:13 -070097 size_t respSize = commandData.size();
Richard Marian Thomaiyar1d82b222018-06-06 14:38:34 +053098 ipmi_ret_t ipmiRC = IPMI_CC_UNSPECIFIED_ERROR;
Richard Marian Thomaiyar472a37b2018-09-06 07:11:07 +053099 std::shared_ptr<session::Session> session =
100 std::get<session::Manager&>(singletonPool)
101 .getSession(handler.sessionID);
102
103 if (session->curPrivLevel >= Entry::getPrivilege())
Richard Marian Thomaiyar1d82b222018-06-06 14:38:34 +0530104 {
Richard Marian Thomaiyar472a37b2018-09-06 07:11:07 +0530105 try
106 {
107 ipmiRC = functor(0, 0, reinterpret_cast<void*>(commandData.data()),
108 reinterpret_cast<void*>(response.data() + 1),
109 &respSize, NULL);
110 }
111 // IPMI command handlers can throw unhandled exceptions, catch those
112 // and return sane error code.
113 catch (const std::exception& e)
114 {
Vernon Maueryfc37e592018-12-19 14:55:15 -0800115 log<level::ERR>("Table: Unspecified error for command",
116 entry("EXCEPTION=%s", e.what()),
117 entry("LUN=%x", int(command.NetFnLun.lun)),
118 entry("NETFN=%x", int(command.NetFnLun.netFn)),
119 entry("CMD=%x", command.cmd));
Richard Marian Thomaiyar472a37b2018-09-06 07:11:07 +0530120 respSize = 0;
121 // fall through
122 }
Richard Marian Thomaiyar1d82b222018-06-06 14:38:34 +0530123 }
Richard Marian Thomaiyar472a37b2018-09-06 07:11:07 +0530124 else
Richard Marian Thomaiyar1d82b222018-06-06 14:38:34 +0530125 {
Richard Marian Thomaiyar1d82b222018-06-06 14:38:34 +0530126 respSize = 0;
Richard Marian Thomaiyar472a37b2018-09-06 07:11:07 +0530127 ipmiRC = IPMI_CC_INSUFFICIENT_PRIVILEGE;
Richard Marian Thomaiyar1d82b222018-06-06 14:38:34 +0530128 }
Tom606e8cb2016-12-02 13:36:14 +0530129 /*
130 * respSize gets you the size of the response data for the IPMI command. The
131 * first byte in a response to the IPMI command is the Completion Code.
132 * So we are inserting completion code as the first byte and incrementing
133 * the response payload size by the size of the completion code.
134 */
135 response[0] = ipmiRC;
136 response.resize(respSize + sizeof(ipmi_ret_t));
137
138 return response;
139}
140
Tom Joseph07181f52016-08-08 08:17:08 -0500141} // namespace command