1 #include "config.h"
2
3 #include "systemintfcmds.hpp"
4
5 #include "host-cmd-manager.hpp"
6 #include "host-interface.hpp"
7
8 #include <ipmid-host/cmd.hpp>
9 #include <ipmid/api.hpp>
10 #include <nlohmann/json.hpp>
11 #include <phosphor-logging/lg2.hpp>
12
13 #include <cstring>
14 #include <fstream>
15
16 void register_netfn_app_functions() __attribute__((constructor));
17
18 using namespace sdbusplus::server::xyz::openbmc_project::control;
19
20 // For accessing Host command manager
21 using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>;
22 extern cmdManagerPtr& ipmid_get_host_cmd_manager();
23
24 //-------------------------------------------------------------------
25 // Called by Host post response from Get_Message_Flags
26 //-------------------------------------------------------------------
27 ipmi::RspType<uint16_t, // id
28 uint8_t, // type
29 uint24_t, // manuf_id
30 uint32_t, // timestamp
31 uint8_t, // netfun
32 uint8_t, // cmd
33 std::array<uint8_t, 4> // data
34 >
ipmiAppReadEventBuffer(ipmi::Context::ptr & ctx)35 ipmiAppReadEventBuffer(ipmi::Context::ptr& ctx)
36 {
37 // require this to be limited to system interface
38 if (ctx->channel != ipmi::channelSystemIface)
39 {
40 return ipmi::responseInvalidCommand();
41 }
42
43 constexpr uint16_t selOemId = 0x5555;
44 constexpr uint8_t selRecordTypeOem = 0xc0;
45
46 // read manufacturer ID from dev_id file
47 static uint24_t manufId{};
48 if (!manufId)
49 {
50 const char* filename = "/usr/share/ipmi-providers/dev_id.json";
51 std::ifstream devIdFile(filename);
52 if (devIdFile.is_open())
53 {
54 auto data = nlohmann::json::parse(devIdFile, nullptr, false);
55 if (!data.is_discarded())
56 {
57 manufId = data.value("manuf_id", 0);
58 }
59 }
60 }
61
62 constexpr uint32_t timestamp{0};
63
64 // per IPMI spec NetFuntion for OEM
65 constexpr uint8_t netfun = 0x3a;
66
67 // Read from the Command Manager queue. What gets returned is a
68 // pair of <command, data> that can be directly used here
69 const auto& [cmd, data0] = ipmid_get_host_cmd_manager()->getNextCommand();
70 constexpr uint8_t dataUnused = 0xff;
71
72 return ipmi::responseSuccess(
73 selOemId, selRecordTypeOem, manufId, timestamp, netfun, cmd,
74 std::to_array<uint8_t>({data0, dataUnused, dataUnused, dataUnused}));
75 }
76
77 //---------------------------------------------------------------------
78 // Called by Host on seeing a SMS_ATN bit set. Return a hardcoded
79 // value of 0x0 to indicate Event Message Buffer is not supported
80 //-------------------------------------------------------------------
ipmiAppGetMessageFlags()81 ipmi::RspType<uint8_t> ipmiAppGetMessageFlags()
82 {
83 // From IPMI spec V2.0 for Get Message Flags Command :
84 // bit:[1] from LSB : 1b = Event Message Buffer Full.
85 // Return as 0 if Event Message Buffer is not supported,
86 // or when the Event Message buffer is disabled.
87 // This path is used to communicate messages to the host
88 // from within the phosphor::host::command::Manager
89 constexpr uint8_t setEventMsgBufferNotSupported = 0x0;
90 return ipmi::responseSuccess(setEventMsgBufferNotSupported);
91 }
92
93 ipmi::RspType<bool, // Receive Message Queue Interrupt Enabled
94 bool, // Event Message Buffer Full Interrupt Enabled
95 bool, // Event Message Buffer Enabled
96 bool, // System Event Logging Enabled
97 uint1_t, // Reserved
98 bool, // OEM 0 enabled
99 bool, // OEM 1 enabled
100 bool // OEM 2 enabled
101 >
ipmiAppGetBMCGlobalEnable()102 ipmiAppGetBMCGlobalEnable()
103 {
104 return ipmi::responseSuccess(true, false, false, true, 0, false, false,
105 false);
106 }
107
ipmiAppSetBMCGlobalEnable(ipmi::Context::ptr ctx,bool receiveMessageQueueInterruptEnabled,bool eventMessageBufferFullInterruptEnabled,bool eventMessageBufferEnabled,bool systemEventLogEnable,uint1_t reserved,bool OEM0Enabled,bool OEM1Enabled,bool OEM2Enabled)108 ipmi::RspType<> ipmiAppSetBMCGlobalEnable(
109 ipmi::Context::ptr ctx, bool receiveMessageQueueInterruptEnabled,
110 bool eventMessageBufferFullInterruptEnabled, bool eventMessageBufferEnabled,
111 bool systemEventLogEnable, uint1_t reserved, bool OEM0Enabled,
112 bool OEM1Enabled, bool OEM2Enabled)
113 {
114 ipmi::ChannelInfo chInfo;
115
116 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
117 {
118 lg2::error("Failed to get Channel Info, channel={CHANNEL}", "CHANNEL",
119 ctx->channel);
120 return ipmi::responseUnspecifiedError();
121 }
122
123 if (chInfo.mediumType !=
124 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface))
125 {
126 lg2::error("Error - supported only in system interface");
127 return ipmi::responseCommandNotAvailable();
128 }
129
130 // Recv Message Queue and SEL are enabled by default.
131 // Event Message buffer are disabled by default (not supported).
132 // Any request that try to change the mask will be rejected
133 if (!receiveMessageQueueInterruptEnabled || !systemEventLogEnable ||
134 eventMessageBufferFullInterruptEnabled || eventMessageBufferEnabled ||
135 OEM0Enabled || OEM1Enabled || OEM2Enabled || reserved)
136 {
137 return ipmi::responseInvalidFieldRequest();
138 }
139
140 return ipmi::responseSuccess();
141 }
142
143 namespace
144 {
145 // Static storage to keep the object alive during process life
146 std::unique_ptr<phosphor::host::command::Host> host
147 __attribute__((init_priority(101)));
148 std::unique_ptr<sdbusplus::server::manager_t> objManager
149 __attribute__((init_priority(101)));
150 } // namespace
151
register_netfn_app_functions()152 void register_netfn_app_functions()
153 {
154 // <Read Event Message Buffer>
155 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
156 ipmi::app::cmdReadEventMessageBuffer,
157 ipmi::Privilege::Admin, ipmiAppReadEventBuffer);
158
159 // <Set BMC Global Enables>
160 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
161 ipmi::app::cmdSetBmcGlobalEnables,
162 ipmi::Privilege::Admin, ipmiAppSetBMCGlobalEnable);
163
164 // <Get BMC Global Enables>
165 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
166 ipmi::app::cmdGetBmcGlobalEnables,
167 ipmi::Privilege::User, ipmiAppGetBMCGlobalEnable);
168
169 // <Get Message Flags>
170 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
171 ipmi::app::cmdGetMessageFlags, ipmi::Privilege::Admin,
172 ipmiAppGetMessageFlags);
173
174 // Create new xyz.openbmc_project.host object on the bus
175 auto objPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + '0';
176
177 std::unique_ptr<sdbusplus::asio::connection>& sdbusp =
178 ipmid_get_sdbus_plus_handler();
179
180 // Add sdbusplus ObjectManager.
181 objManager = std::make_unique<sdbusplus::server::manager_t>(
182 *sdbusp, CONTROL_HOST_OBJ_MGR);
183
184 host = std::make_unique<phosphor::host::command::Host>(
185 *sdbusp, objPath.c_str());
186 sdbusp->request_name(CONTROL_HOST_BUSNAME);
187
188 return;
189 }
190