blob: e911bc6923767aaac05db41af59f21a6f0e0a407 [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 Mauery66501642018-07-30 09:07:10 -07009#include <main.hpp>
Vernon Mauery9e801a22018-10-12 13:20:49 -070010#include <phosphor-logging/elog-errors.hpp>
11#include <phosphor-logging/log.hpp>
Vernon Mauery66501642018-07-30 09:07:10 -070012#include <user_channel/user_layer.hpp>
Vernon Maueryf41a5542018-10-15 16:04:17 -070013#include <xyz/openbmc_project/Common/error.hpp>
Vernon Mauery9e801a22018-10-12 13:20:49 -070014
Vernon Mauery66501642018-07-30 09:07:10 -070015using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Nagaraju Goruganti1d9d4162018-03-22 01:27:37 -050016using namespace phosphor::logging;
Tom Joseph07181f52016-08-08 08:17:08 -050017
Vernon Mauery66501642018-07-30 09:07:10 -070018namespace ipmi
19{
20using Value = sdbusplus::message::variant<bool, uint8_t, int16_t, uint16_t,
21 int32_t, uint32_t, int64_t, uint64_t,
22 double, std::string>;
23
24} // namespace ipmi
25
Tom Joseph07181f52016-08-08 08:17:08 -050026namespace command
27{
28
29void Table::registerCommand(CommandID inCommand, std::unique_ptr<Entry>&& entry)
30{
Feist, Jamesbd45aae2017-10-26 15:06:13 -070031 auto& command = commandTable[inCommand.command];
32
33 if (command)
34 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070035 log<level::DEBUG>(
36 "Already Registered",
Vernon Mauery66501642018-07-30 09:07:10 -070037 phosphor::logging::entry("SKIPPED_ENTRY=0x%x", inCommand.command));
Feist, Jamesbd45aae2017-10-26 15:06:13 -070038 return;
39 }
40
Feist, Jamesbd45aae2017-10-26 15:06:13 -070041 command = std::move(entry);
Tom Joseph07181f52016-08-08 08:17:08 -050042}
43
44std::vector<uint8_t> Table::executeCommand(uint32_t inCommand,
45 std::vector<uint8_t>& commandData,
46 const message::Handler& handler)
47{
48 using namespace std::chrono_literals;
49
50 std::vector<uint8_t> response;
51
52 auto iterator = commandTable.find(inCommand);
53
54 if (iterator == commandTable.end())
55 {
Vernon Mauery66501642018-07-30 09:07:10 -070056 CommandID command(inCommand);
57
58 auto bus = getSdBus();
59 // forward the request onto the main ipmi queue
60 auto method = bus->new_method_call(
61 "xyz.openbmc_project.Ipmi.Host", "/xyz/openbmc_project/Ipmi",
62 "xyz.openbmc_project.Ipmi.Server", "execute");
63 uint8_t lun = command.lun();
64 uint8_t netFn = command.netFn();
65 uint8_t cmd = command.cmd();
66 std::shared_ptr<session::Session> session =
67 std::get<session::Manager&>(singletonPool)
68 .getSession(handler.sessionID);
69 std::map<std::string, ipmi::Value> options = {
70 {"userId", ipmi::Value(ipmi::ipmiUserGetUserId(session->userName))},
71 {"privilege", ipmi::Value(static_cast<int>(session->curPrivLevel))},
72 };
73 method.append(netFn, lun, cmd, commandData, options);
74 using IpmiDbusRspType = std::tuple<uint8_t, uint8_t, uint8_t, uint8_t,
75 std::vector<uint8_t>>;
76 IpmiDbusRspType rspTuple;
77 try
78 {
79 auto reply = bus->call(method);
80 reply.read(rspTuple);
81 }
82 catch (const sdbusplus::exception::SdBusError& e)
83 {
84 response.push_back(IPMI_CC_UNSPECIFIED_ERROR);
85 log<level::ERR>("Error sending command to ipmi queue");
86 elog<InternalFailure>();
87 }
88 auto& [rnetFn, rlun, rcmd, cc, responseData] = rspTuple;
89 if (uint8_t(netFn + 1) != rnetFn || rlun != lun || rcmd != cmd)
90 {
91 response.push_back(IPMI_CC_UNSPECIFIED_ERROR);
92 log<level::ERR>("DBus call/response mismatch from ipmi queue");
93 elog<InternalFailure>();
94 }
95 else
96 {
97 response.reserve(1 + responseData.size());
98 response.push_back(cc);
99 response.insert(response.end(), responseData.begin(),
100 responseData.end());
101 }
Tom Joseph07181f52016-08-08 08:17:08 -0500102 }
103 else
104 {
105 auto start = std::chrono::steady_clock::now();
106
107 response = iterator->second->executeCommand(commandData, handler);
108
109 auto end = std::chrono::steady_clock::now();
110
Vernon Mauery9e801a22018-10-12 13:20:49 -0700111 auto elapsedSeconds =
112 std::chrono::duration_cast<std::chrono::seconds>(end - start);
Tom Joseph07181f52016-08-08 08:17:08 -0500113
114 // If command time execution time exceeds 2 seconds, log a time
115 // exceeded message
116 if (elapsedSeconds > 2s)
117 {
Vernon Maueryfc37e592018-12-19 14:55:15 -0800118 log<level::ERR>("IPMI command timed out",
119 entry("DELAY=%d", elapsedSeconds.count()));
Tom Joseph07181f52016-08-08 08:17:08 -0500120 }
121 }
122 return response;
123}
124
Vernon Mauery9e801a22018-10-12 13:20:49 -0700125std::vector<uint8_t>
126 NetIpmidEntry::executeCommand(std::vector<uint8_t>& commandData,
127 const message::Handler& handler)
Tom Joseph07181f52016-08-08 08:17:08 -0500128{
129 std::vector<uint8_t> errResponse;
130
131 // Check if the command qualifies to be run prior to establishing a session
132 if (!sessionless && (handler.sessionID == session::SESSION_ZERO))
133 {
134 errResponse.resize(1);
135 errResponse[0] = IPMI_CC_INSUFFICIENT_PRIVILEGE;
Vernon Maueryfc37e592018-12-19 14:55:15 -0800136 log<level::INFO>("Table: Insufficient privilege for command",
Vernon Mauery66501642018-07-30 09:07:10 -0700137 entry("LUN=%x", command.lun()),
138 entry("NETFN=%x", command.netFn()),
139 entry("CMD=%x", command.cmd()));
Tom Joseph07181f52016-08-08 08:17:08 -0500140 return errResponse;
141 }
142
143 return functor(commandData, handler);
144}
145
Tom Joseph07181f52016-08-08 08:17:08 -0500146} // namespace command