blob: 26859a59c8cd9e9a8d27c4add711758cc063e9d0 [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>
9#include <iostream>
10#include <phosphor-logging/elog-errors.hpp>
11#include <phosphor-logging/log.hpp>
Vernon Maueryf41a5542018-10-15 16:04:17 -070012#include <xyz/openbmc_project/Common/error.hpp>
Vernon Mauery9e801a22018-10-12 13:20:49 -070013
Nagaraju Goruganti1d9d4162018-03-22 01:27:37 -050014using namespace phosphor::logging;
Tom Joseph07181f52016-08-08 08:17:08 -050015
16namespace command
17{
18
19void Table::registerCommand(CommandID inCommand, std::unique_ptr<Entry>&& entry)
20{
Feist, Jamesbd45aae2017-10-26 15:06:13 -070021 auto& command = commandTable[inCommand.command];
22
23 if (command)
24 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070025 log<level::DEBUG>(
26 "Already Registered",
27 phosphor::logging::entry("SKIPPED_ENTRY=0x%x",
28 uint32_t(inCommand.command)));
Feist, Jamesbd45aae2017-10-26 15:06:13 -070029 return;
30 }
31
Feist, Jamesbd45aae2017-10-26 15:06:13 -070032 command = std::move(entry);
Tom Joseph07181f52016-08-08 08:17:08 -050033}
34
35std::vector<uint8_t> Table::executeCommand(uint32_t inCommand,
36 std::vector<uint8_t>& commandData,
37 const message::Handler& handler)
38{
39 using namespace std::chrono_literals;
40
41 std::vector<uint8_t> response;
42
43 auto iterator = commandTable.find(inCommand);
44
45 if (iterator == commandTable.end())
46 {
Tom Joseph07181f52016-08-08 08:17:08 -050047 response.resize(1);
48 response[0] = IPMI_CC_INVALID;
49 }
50 else
51 {
52 auto start = std::chrono::steady_clock::now();
53
54 response = iterator->second->executeCommand(commandData, handler);
55
56 auto end = std::chrono::steady_clock::now();
57
Vernon Mauery9e801a22018-10-12 13:20:49 -070058 auto elapsedSeconds =
59 std::chrono::duration_cast<std::chrono::seconds>(end - start);
Tom Joseph07181f52016-08-08 08:17:08 -050060
61 // If command time execution time exceeds 2 seconds, log a time
62 // exceeded message
63 if (elapsedSeconds > 2s)
64 {
65 std::cerr << "E> IPMI command timed out:Elapsed time = "
Vernon Mauery9e801a22018-10-12 13:20:49 -070066 << elapsedSeconds.count() << "s"
67 << "\n";
Tom Joseph07181f52016-08-08 08:17:08 -050068 }
69 }
70 return response;
71}
72
Vernon Mauery9e801a22018-10-12 13:20:49 -070073std::vector<uint8_t>
74 NetIpmidEntry::executeCommand(std::vector<uint8_t>& commandData,
75 const message::Handler& handler)
Tom Joseph07181f52016-08-08 08:17:08 -050076{
77 std::vector<uint8_t> errResponse;
78
79 // Check if the command qualifies to be run prior to establishing a session
80 if (!sessionless && (handler.sessionID == session::SESSION_ZERO))
81 {
82 errResponse.resize(1);
83 errResponse[0] = IPMI_CC_INSUFFICIENT_PRIVILEGE;
84 std::cerr << "E> Table::Not enough privileges for command 0x"
85 << std::hex << command.command << "\n";
86 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 {
115 std::cerr << "E> Unspecified error for command 0x" << std::hex
116 << command.command << " - " << e.what() << "\n";
117 respSize = 0;
118 // fall through
119 }
Richard Marian Thomaiyar1d82b222018-06-06 14:38:34 +0530120 }
Richard Marian Thomaiyar472a37b2018-09-06 07:11:07 +0530121 else
Richard Marian Thomaiyar1d82b222018-06-06 14:38:34 +0530122 {
Richard Marian Thomaiyar1d82b222018-06-06 14:38:34 +0530123 respSize = 0;
Richard Marian Thomaiyar472a37b2018-09-06 07:11:07 +0530124 ipmiRC = IPMI_CC_INSUFFICIENT_PRIVILEGE;
Richard Marian Thomaiyar1d82b222018-06-06 14:38:34 +0530125 }
Tom606e8cb2016-12-02 13:36:14 +0530126 /*
127 * respSize gets you the size of the response data for the IPMI command. The
128 * first byte in a response to the IPMI command is the Completion Code.
129 * So we are inserting completion code as the first byte and incrementing
130 * the response payload size by the size of the completion code.
131 */
132 response[0] = ipmiRC;
133 response.resize(respSize + sizeof(ipmi_ret_t));
134
135 return response;
136}
137
Tom Joseph07181f52016-08-08 08:17:08 -0500138} // namespace command