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