blob: 8e472880d4ff230aa502e029d28b0ebcf5af7b54 [file] [log] [blame]
Patrick Venture0b02be92018-08-31 11:55:55 -07001#include <arpa/inet.h>
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05302#include <fcntl.h>
Xo Wang87651332017-08-11 10:17:59 -07003#include <limits.h>
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05304#include <linux/i2c-dev.h>
5#include <linux/i2c.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07006#include <mapper.h>
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05307#include <sys/ioctl.h>
8#include <sys/stat.h>
9#include <sys/types.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070010#include <systemd/sd-bus.h>
Xo Wang87651332017-08-11 10:17:59 -070011#include <unistd.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070012
Patrick Venture3a5071a2018-09-12 13:27:42 -070013#include <algorithm>
Vernon Mauery0120b682019-03-25 13:08:54 -070014#include <app/channel.hpp>
15#include <app/watchdog.hpp>
16#include <apphandler.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070017#include <array>
Willy Tu886d6842022-06-03 02:50:47 -070018#include <charconv>
Patrick Venture3a5071a2018-09-12 13:27:42 -070019#include <cstddef>
Vernon Mauery0120b682019-03-25 13:08:54 -070020#include <cstdint>
Vernon Mauerybdda8002019-02-26 10:18:51 -080021#include <filesystem>
Patrick Venture3a5071a2018-09-12 13:27:42 -070022#include <fstream>
Vernon Mauery0120b682019-03-25 13:08:54 -070023#include <ipmid/api.hpp>
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +000024#include <ipmid/sessiondef.hpp>
25#include <ipmid/sessionhelper.hpp>
Vernon Mauery33250242019-03-12 16:49:26 -070026#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070027#include <ipmid/utils.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070028#include <memory>
Patrick Venture46470a32018-09-07 19:26:25 -070029#include <nlohmann/json.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070030#include <phosphor-logging/elog-errors.hpp>
31#include <phosphor-logging/log.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070032#include <sdbusplus/message/types.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070033#include <string>
Willy Tu886d6842022-06-03 02:50:47 -070034#include <string_view>
Vernon Mauery0120b682019-03-25 13:08:54 -070035#include <sys_info_param.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070036#include <tuple>
37#include <vector>
38#include <xyz/openbmc_project/Common/error.hpp>
Yong Li18d77262018-10-09 01:59:45 +080039#include <xyz/openbmc_project/Control/Power/ACPIPowerState/server.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070040#include <xyz/openbmc_project/Software/Activation/server.hpp>
41#include <xyz/openbmc_project/Software/Version/server.hpp>
42#include <xyz/openbmc_project/State/BMC/server.hpp>
Ratan Guptab8e99552017-07-27 07:07:48 +053043
Patrick Venture0b02be92018-08-31 11:55:55 -070044extern sd_bus* bus;
vishwabmcba0bd5f2015-09-30 16:50:23 +053045
Alexander Amelkinba19c182018-09-04 15:49:36 +030046constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC";
47constexpr auto bmc_state_property = "CurrentBMCState";
Marri Devender Rao5e007a52018-01-08 06:18:36 -060048
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060049static constexpr auto redundancyIntf =
50 "xyz.openbmc_project.Software.RedundancyPriority";
Patrick Venture0b02be92018-08-31 11:55:55 -070051static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version";
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060052static constexpr auto activationIntf =
53 "xyz.openbmc_project.Software.Activation";
54static constexpr auto softwareRoot = "/xyz/openbmc_project/software";
55
Chris Austen6caf28b2015-10-13 12:40:40 -050056void register_netfn_app_functions() __attribute__((constructor));
vishwabmcba0bd5f2015-09-30 16:50:23 +053057
Ratan Guptab8e99552017-07-27 07:07:48 +053058using namespace phosphor::logging;
59using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060060using Version = sdbusplus::xyz::openbmc_project::Software::server::Version;
61using Activation =
62 sdbusplus::xyz::openbmc_project::Software::server::Activation;
Alexander Amelkinba19c182018-09-04 15:49:36 +030063using BMC = sdbusplus::xyz::openbmc_project::State::server::BMC;
Vernon Mauery185b9f82018-07-20 10:52:36 -070064namespace fs = std::filesystem;
Ratan Guptab8e99552017-07-27 07:07:48 +053065
Yong Libd0503a2019-08-22 17:17:17 +080066#ifdef ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +053067typedef struct
68{
69 uint8_t busId;
70 uint8_t slaveAddr;
71 uint8_t slaveAddrMask;
72 std::vector<uint8_t> data;
73 std::vector<uint8_t> dataMask;
74} i2cMasterWRWhitelist;
75
76static std::vector<i2cMasterWRWhitelist>& getWRWhitelist()
77{
78 static std::vector<i2cMasterWRWhitelist> wrWhitelist;
79 return wrWhitelist;
80}
81
82static constexpr const char* i2cMasterWRWhitelistFile =
83 "/usr/share/ipmi-providers/master_write_read_white_list.json";
84
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +053085static constexpr const char* filtersStr = "filters";
86static constexpr const char* busIdStr = "busId";
87static constexpr const char* slaveAddrStr = "slaveAddr";
88static constexpr const char* slaveAddrMaskStr = "slaveAddrMask";
89static constexpr const char* cmdStr = "command";
90static constexpr const char* cmdMaskStr = "commandMask";
91static constexpr int base_16 = 16;
Yong Libd0503a2019-08-22 17:17:17 +080092#endif // ENABLE_I2C_WHITELIST_CHECK
Joshi-Mansi7fd91fa2021-06-11 07:18:15 +053093static constexpr uint8_t maxIPMIWriteReadSize = 255;
jayaprakash Mutyala3c5e4132020-04-27 23:00:05 +000094static constexpr uint8_t oemCmdStart = 192;
95static constexpr uint8_t oemCmdEnd = 255;
96static constexpr uint8_t invalidParamSelectorStart = 8;
97static constexpr uint8_t invalidParamSelectorEnd = 191;
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +053098
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060099/**
100 * @brief Returns the Version info from primary s/w object
101 *
102 * Get the Version info from the active s/w object which is having high
103 * "Priority" value(a smaller number is a higher priority) and "Purpose"
104 * is "BMC" from the list of all s/w objects those are implementing
105 * RedundancyPriority interface from the given softwareRoot path.
106 *
107 * @return On success returns the Version info from primary s/w object.
108 *
109 */
Vernon Maueryea1c4012019-05-24 13:26:16 -0700110std::string getActiveSoftwareVersionInfo(ipmi::Context::ptr ctx)
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600111{
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600112 std::string revision{};
Vernon Mauery86a50822019-03-25 13:11:36 -0700113 ipmi::ObjectTree objectTree;
114 try
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600115 {
Vernon Mauery86a50822019-03-25 13:11:36 -0700116 objectTree =
Vernon Maueryea1c4012019-05-24 13:26:16 -0700117 ipmi::getAllDbusObjects(*ctx->bus, softwareRoot, redundancyIntf);
Vernon Mauery86a50822019-03-25 13:11:36 -0700118 }
Patrick Williams5d82f472022-07-22 19:26:53 -0500119 catch (const sdbusplus::exception_t& e)
Vernon Mauery86a50822019-03-25 13:11:36 -0700120 {
121 log<level::ERR>("Failed to fetch redundancy object from dbus",
122 entry("INTERFACE=%s", redundancyIntf),
123 entry("ERRMSG=%s", e.what()));
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600124 elog<InternalFailure>();
125 }
126
127 auto objectFound = false;
128 for (auto& softObject : objectTree)
129 {
Vernon Mauery86a50822019-03-25 13:11:36 -0700130 auto service =
Vernon Maueryea1c4012019-05-24 13:26:16 -0700131 ipmi::getService(*ctx->bus, redundancyIntf, softObject.first);
Vernon Mauery86a50822019-03-25 13:11:36 -0700132 auto objValueTree =
Vernon Maueryea1c4012019-05-24 13:26:16 -0700133 ipmi::getManagedObjects(*ctx->bus, service, softwareRoot);
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600134
135 auto minPriority = 0xFF;
136 for (const auto& objIter : objValueTree)
137 {
138 try
139 {
140 auto& intfMap = objIter.second;
141 auto& redundancyPriorityProps = intfMap.at(redundancyIntf);
142 auto& versionProps = intfMap.at(versionIntf);
143 auto& activationProps = intfMap.at(activationIntf);
Vernon Maueryf442e112019-04-09 11:44:36 -0700144 auto priority =
145 std::get<uint8_t>(redundancyPriorityProps.at("Priority"));
William A. Kennington III4c008022018-10-12 17:18:14 -0700146 auto purpose =
Vernon Maueryf442e112019-04-09 11:44:36 -0700147 std::get<std::string>(versionProps.at("Purpose"));
148 auto activation =
149 std::get<std::string>(activationProps.at("Activation"));
William A. Kennington III4c008022018-10-12 17:18:14 -0700150 auto version =
Vernon Maueryf442e112019-04-09 11:44:36 -0700151 std::get<std::string>(versionProps.at("Version"));
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600152 if ((Version::convertVersionPurposeFromString(purpose) ==
153 Version::VersionPurpose::BMC) &&
154 (Activation::convertActivationsFromString(activation) ==
155 Activation::Activations::Active))
156 {
157 if (priority < minPriority)
158 {
159 minPriority = priority;
160 objectFound = true;
161 revision = std::move(version);
162 }
163 }
164 }
165 catch (const std::exception& e)
166 {
167 log<level::ERR>(e.what());
168 }
169 }
170 }
171
172 if (!objectFound)
173 {
174 log<level::ERR>("Could not found an BMC software Object");
175 elog<InternalFailure>();
176 }
177
178 return revision;
179}
180
Alexander Amelkinba19c182018-09-04 15:49:36 +0300181bool getCurrentBmcState()
182{
Patrick Williams5d82f472022-07-22 19:26:53 -0500183 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Alexander Amelkinba19c182018-09-04 15:49:36 +0300184
185 // Get the Inventory object implementing the BMC interface
186 ipmi::DbusObjectInfo bmcObject =
187 ipmi::getDbusObject(bus, bmc_state_interface);
188 auto variant =
189 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first,
190 bmc_state_interface, bmc_state_property);
191
Vernon Maueryf442e112019-04-09 11:44:36 -0700192 return std::holds_alternative<std::string>(variant) &&
193 BMC::convertBMCStateFromString(std::get<std::string>(variant)) ==
194 BMC::BMCState::Ready;
Alexander Amelkinba19c182018-09-04 15:49:36 +0300195}
196
Patrick Venture94930a12019-04-30 10:01:58 -0700197bool getCurrentBmcStateWithFallback(const bool fallbackAvailability)
198{
199 try
200 {
201 return getCurrentBmcState();
202 }
203 catch (...)
204 {
205 // Nothing provided the BMC interface, therefore return whatever was
206 // configured as the default.
207 return fallbackAvailability;
208 }
209}
210
Yong Li18d77262018-10-09 01:59:45 +0800211namespace acpi_state
212{
213using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
214
215const static constexpr char* acpiObjPath =
216 "/xyz/openbmc_project/control/host0/acpi_power_state";
217const static constexpr char* acpiInterface =
218 "xyz.openbmc_project.Control.Power.ACPIPowerState";
219const static constexpr char* sysACPIProp = "SysACPIStatus";
220const static constexpr char* devACPIProp = "DevACPIStatus";
221
222enum class PowerStateType : uint8_t
223{
224 sysPowerState = 0x00,
225 devPowerState = 0x01,
226};
227
228// Defined in 20.6 of ipmi doc
229enum class PowerState : uint8_t
230{
231 s0G0D0 = 0x00,
232 s1D1 = 0x01,
233 s2D2 = 0x02,
234 s3D3 = 0x03,
235 s4 = 0x04,
236 s5G2 = 0x05,
237 s4S5 = 0x06,
238 g3 = 0x07,
239 sleep = 0x08,
240 g1Sleep = 0x09,
241 override = 0x0a,
242 legacyOn = 0x20,
243 legacyOff = 0x21,
244 unknown = 0x2a,
245 noChange = 0x7f,
246};
247
248static constexpr uint8_t stateChanged = 0x80;
249
Yong Li18d77262018-10-09 01:59:45 +0800250std::map<ACPIPowerState::ACPI, PowerState> dbusToIPMI = {
251 {ACPIPowerState::ACPI::S0_G0_D0, PowerState::s0G0D0},
252 {ACPIPowerState::ACPI::S1_D1, PowerState::s1D1},
253 {ACPIPowerState::ACPI::S2_D2, PowerState::s2D2},
254 {ACPIPowerState::ACPI::S3_D3, PowerState::s3D3},
255 {ACPIPowerState::ACPI::S4, PowerState::s4},
256 {ACPIPowerState::ACPI::S5_G2, PowerState::s5G2},
257 {ACPIPowerState::ACPI::S4_S5, PowerState::s4S5},
258 {ACPIPowerState::ACPI::G3, PowerState::g3},
259 {ACPIPowerState::ACPI::SLEEP, PowerState::sleep},
260 {ACPIPowerState::ACPI::G1_SLEEP, PowerState::g1Sleep},
261 {ACPIPowerState::ACPI::OVERRIDE, PowerState::override},
262 {ACPIPowerState::ACPI::LEGACY_ON, PowerState::legacyOn},
263 {ACPIPowerState::ACPI::LEGACY_OFF, PowerState::legacyOff},
264 {ACPIPowerState::ACPI::Unknown, PowerState::unknown}};
265
266bool isValidACPIState(acpi_state::PowerStateType type, uint8_t state)
267{
268 if (type == acpi_state::PowerStateType::sysPowerState)
269 {
270 if ((state <= static_cast<uint8_t>(acpi_state::PowerState::override)) ||
271 (state == static_cast<uint8_t>(acpi_state::PowerState::legacyOn)) ||
272 (state ==
273 static_cast<uint8_t>(acpi_state::PowerState::legacyOff)) ||
274 (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
275 (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
276 {
277 return true;
278 }
279 else
280 {
281 return false;
282 }
283 }
284 else if (type == acpi_state::PowerStateType::devPowerState)
285 {
286 if ((state <= static_cast<uint8_t>(acpi_state::PowerState::s3D3)) ||
287 (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
288 (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
289 {
290 return true;
291 }
292 else
293 {
294 return false;
295 }
296 }
297 else
298 {
299 return false;
300 }
301 return false;
302}
303} // namespace acpi_state
304
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +0000305/** @brief implements Set ACPI Power State command
306 * @param sysAcpiState - ACPI system power state to set
307 * @param devAcpiState - ACPI device power state to set
308 *
309 * @return IPMI completion code on success
310 **/
311ipmi::RspType<> ipmiSetAcpiPowerState(uint8_t sysAcpiState,
312 uint8_t devAcpiState)
Chris Austen6caf28b2015-10-13 12:40:40 -0500313{
Yong Li18d77262018-10-09 01:59:45 +0800314 auto s = static_cast<uint8_t>(acpi_state::PowerState::unknown);
Yong Li18d77262018-10-09 01:59:45 +0800315
Patrick Williams5d82f472022-07-22 19:26:53 -0500316 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Yong Li18d77262018-10-09 01:59:45 +0800317
318 auto value = acpi_state::ACPIPowerState::ACPI::Unknown;
319
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +0000320 if (sysAcpiState & acpi_state::stateChanged)
Yong Li18d77262018-10-09 01:59:45 +0800321 {
322 // set system power state
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +0000323 s = sysAcpiState & ~acpi_state::stateChanged;
Yong Li18d77262018-10-09 01:59:45 +0800324
325 if (!acpi_state::isValidACPIState(
326 acpi_state::PowerStateType::sysPowerState, s))
327 {
328 log<level::ERR>("set_acpi_power sys invalid input",
329 entry("S=%x", s));
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +0000330 return ipmi::responseParmOutOfRange();
Yong Li18d77262018-10-09 01:59:45 +0800331 }
332
333 // valid input
334 if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
335 {
336 log<level::DEBUG>("No change for system power state");
337 }
338 else
339 {
340 auto found = std::find_if(
341 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
342 [&s](const auto& iter) {
343 return (static_cast<uint8_t>(iter.second) == s);
344 });
345
346 value = found->first;
347
348 try
349 {
350 auto acpiObject =
351 ipmi::getDbusObject(bus, acpi_state::acpiInterface);
352 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
353 acpi_state::acpiInterface,
354 acpi_state::sysACPIProp,
355 convertForMessage(value));
356 }
357 catch (const InternalFailure& e)
358 {
359 log<level::ERR>("Failed in set ACPI system property",
360 entry("EXCEPTION=%s", e.what()));
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +0000361 return ipmi::responseUnspecifiedError();
Yong Li18d77262018-10-09 01:59:45 +0800362 }
363 }
364 }
365 else
366 {
367 log<level::DEBUG>("Do not change system power state");
368 }
369
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +0000370 if (devAcpiState & acpi_state::stateChanged)
Yong Li18d77262018-10-09 01:59:45 +0800371 {
372 // set device power state
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +0000373 s = devAcpiState & ~acpi_state::stateChanged;
Yong Li18d77262018-10-09 01:59:45 +0800374 if (!acpi_state::isValidACPIState(
375 acpi_state::PowerStateType::devPowerState, s))
376 {
377 log<level::ERR>("set_acpi_power dev invalid input",
378 entry("S=%x", s));
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +0000379 return ipmi::responseParmOutOfRange();
Yong Li18d77262018-10-09 01:59:45 +0800380 }
381
382 // valid input
383 if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
384 {
385 log<level::DEBUG>("No change for device power state");
386 }
387 else
388 {
389 auto found = std::find_if(
390 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
391 [&s](const auto& iter) {
392 return (static_cast<uint8_t>(iter.second) == s);
393 });
394
395 value = found->first;
396
397 try
398 {
399 auto acpiObject =
400 ipmi::getDbusObject(bus, acpi_state::acpiInterface);
401 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
402 acpi_state::acpiInterface,
403 acpi_state::devACPIProp,
404 convertForMessage(value));
405 }
406 catch (const InternalFailure& e)
407 {
408 log<level::ERR>("Failed in set ACPI device property",
409 entry("EXCEPTION=%s", e.what()));
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +0000410 return ipmi::responseUnspecifiedError();
Yong Li18d77262018-10-09 01:59:45 +0800411 }
412 }
413 }
414 else
415 {
416 log<level::DEBUG>("Do not change device power state");
417 }
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +0000418 return ipmi::responseSuccess();
Yong Li18d77262018-10-09 01:59:45 +0800419}
420
Deepak Kumar Sahu4e6d2572019-05-07 19:53:37 +0000421/**
422 * @brief implements the get ACPI power state command
423 *
424 * @return IPMI completion code plus response data on success.
425 * - ACPI system power state
426 * - ACPI device power state
427 **/
428ipmi::RspType<uint8_t, // acpiSystemPowerState
429 uint8_t // acpiDevicePowerState
430 >
431 ipmiGetAcpiPowerState()
Yong Li18d77262018-10-09 01:59:45 +0800432{
Deepak Kumar Sahu4e6d2572019-05-07 19:53:37 +0000433 uint8_t sysAcpiState;
434 uint8_t devAcpiState;
Yong Li18d77262018-10-09 01:59:45 +0800435
Patrick Williams5d82f472022-07-22 19:26:53 -0500436 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Yong Li18d77262018-10-09 01:59:45 +0800437
Yong Li18d77262018-10-09 01:59:45 +0800438 try
439 {
440 auto acpiObject = ipmi::getDbusObject(bus, acpi_state::acpiInterface);
441
442 auto sysACPIVal = ipmi::getDbusProperty(
443 bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
444 acpi_state::sysACPIProp);
445 auto sysACPI = acpi_state::ACPIPowerState::convertACPIFromString(
Vernon Maueryf442e112019-04-09 11:44:36 -0700446 std::get<std::string>(sysACPIVal));
Deepak Kumar Sahu4e6d2572019-05-07 19:53:37 +0000447 sysAcpiState = static_cast<uint8_t>(acpi_state::dbusToIPMI.at(sysACPI));
Yong Li18d77262018-10-09 01:59:45 +0800448
449 auto devACPIVal = ipmi::getDbusProperty(
450 bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
451 acpi_state::devACPIProp);
452 auto devACPI = acpi_state::ACPIPowerState::convertACPIFromString(
Vernon Maueryf442e112019-04-09 11:44:36 -0700453 std::get<std::string>(devACPIVal));
Deepak Kumar Sahu4e6d2572019-05-07 19:53:37 +0000454 devAcpiState = static_cast<uint8_t>(acpi_state::dbusToIPMI.at(devACPI));
Yong Li18d77262018-10-09 01:59:45 +0800455 }
456 catch (const InternalFailure& e)
457 {
Deepak Kumar Sahu4e6d2572019-05-07 19:53:37 +0000458 return ipmi::responseUnspecifiedError();
Yong Li18d77262018-10-09 01:59:45 +0800459 }
Deepak Kumar Sahu4e6d2572019-05-07 19:53:37 +0000460
461 return ipmi::responseSuccess(sysAcpiState, devAcpiState);
Chris Austen6caf28b2015-10-13 12:40:40 -0500462}
463
Chris Austen7303bdc2016-04-17 11:50:54 -0500464typedef struct
465{
466 char major;
467 char minor;
Chris Austen176c9652016-04-30 16:32:17 -0500468 uint16_t d[2];
Vernon Mauery86a50822019-03-25 13:11:36 -0700469} Revision;
Chris Austen7303bdc2016-04-17 11:50:54 -0500470
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600471/* Currently supports the vx.x-x-[-x] and v1.x.x-x-[-x] format. It will */
472/* return -1 if not in those formats, this routine knows how to parse */
Chris Austen7303bdc2016-04-17 11:50:54 -0500473/* version = v0.6-19-gf363f61-dirty */
474/* ^ ^ ^^ ^ */
475/* | | |----------|-- additional details */
476/* | |---------------- Minor */
477/* |------------------ Major */
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600478/* and version = v1.99.10-113-g65edf7d-r3-0-g9e4f715 */
479/* ^ ^ ^^ ^ */
480/* | | |--|---------- additional details */
481/* | |---------------- Minor */
482/* |------------------ Major */
Chris Austen7303bdc2016-04-17 11:50:54 -0500483/* Additional details : If the option group exists it will force Auxiliary */
484/* Firmware Revision Information 4th byte to 1 indicating the build was */
485/* derived with additional edits */
Willy Tu886d6842022-06-03 02:50:47 -0700486int convertVersion(std::string_view s, Revision& rev)
Chris Austen7303bdc2016-04-17 11:50:54 -0500487{
Willy Tu886d6842022-06-03 02:50:47 -0700488 std::string_view token;
Chris Austen176c9652016-04-30 16:32:17 -0500489 uint16_t commits;
Chris Austen7303bdc2016-04-17 11:50:54 -0500490
Patrick Venture0b02be92018-08-31 11:55:55 -0700491 auto location = s.find_first_of('v');
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600492 if (location != std::string::npos)
493 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700494 s = s.substr(location + 1);
Chris Austen176c9652016-04-30 16:32:17 -0500495 }
Chris Austen7303bdc2016-04-17 11:50:54 -0500496
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600497 if (!s.empty())
498 {
499 location = s.find_first_of(".");
500 if (location != std::string::npos)
501 {
Willy Tu886d6842022-06-03 02:50:47 -0700502 std::string_view majorView = s.substr(0, location);
503 auto [ptr, ec]{
504 std::from_chars(majorView.begin(), majorView.end(), rev.major)};
505 if (ec != std::errc())
506 {
507 throw std::runtime_error(
508 "failed to convert major string to uint8_t: " +
509 std::make_error_code(ec).message());
510 }
511 if (ptr != majorView.begin() + majorView.size())
512 {
513 throw std::runtime_error(
514 "converted invalid characters in major string");
515 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700516 token = s.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600517 }
Chris Austen176c9652016-04-30 16:32:17 -0500518
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600519 if (!token.empty())
520 {
521 location = token.find_first_of(".-");
522 if (location != std::string::npos)
523 {
Willy Tu886d6842022-06-03 02:50:47 -0700524 std::string_view minorView = token.substr(0, location);
525 auto [ptr, ec]{std::from_chars(minorView.begin(),
526 minorView.end(), rev.minor)};
527 if (ec != std::errc())
528 {
529 throw std::runtime_error(
530 "failed to convert minor string to uint8_t: " +
531 std::make_error_code(ec).message());
532 }
533 if (ptr != minorView.begin() + minorView.size())
534 {
535 throw std::runtime_error(
536 "converted invalid characters in minor string");
537 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700538 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600539 }
540 }
Chris Austen7303bdc2016-04-17 11:50:54 -0500541
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600542 // Capture the number of commits on top of the minor tag.
543 // I'm using BE format like the ipmi spec asked for
544 location = token.find_first_of(".-");
545 if (!token.empty())
546 {
Willy Tu886d6842022-06-03 02:50:47 -0700547 std::string_view commitView = token.substr(0, location);
548 auto [ptr, ec]{std::from_chars(commitView.begin(), commitView.end(),
549 commits, 16)};
550 if (ec != std::errc())
551 {
552 throw std::runtime_error(
553 "failed to convert commit string to uint16_t: " +
554 std::make_error_code(ec).message());
555 }
556 if (ptr != commitView.begin() + commitView.size())
557 {
558 throw std::runtime_error(
559 "converted invalid characters in commit string");
560 }
Vernon Mauery86a50822019-03-25 13:11:36 -0700561 rev.d[0] = (commits >> 8) | (commits << 8);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600562
563 // commit number we skip
564 location = token.find_first_of(".-");
565 if (location != std::string::npos)
566 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700567 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600568 }
569 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700570 else
571 {
Vernon Mauery86a50822019-03-25 13:11:36 -0700572 rev.d[0] = 0;
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600573 }
574
575 if (location != std::string::npos)
576 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700577 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600578 }
579
580 // Any value of the optional parameter forces it to 1
581 location = token.find_first_of(".-");
582 if (location != std::string::npos)
583 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700584 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600585 }
586 commits = (!token.empty()) ? 1 : 0;
587
Patrick Venture0b02be92018-08-31 11:55:55 -0700588 // We do this operation to get this displayed in least significant bytes
589 // of ipmitool device id command.
Vernon Mauery86a50822019-03-25 13:11:36 -0700590 rev.d[1] = (commits >> 8) | (commits << 8);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600591 }
592
Chris Austen7303bdc2016-04-17 11:50:54 -0500593 return 0;
594}
595
Vernon Maueryea1c4012019-05-24 13:26:16 -0700596/* @brief: Implement the Get Device ID IPMI command per the IPMI spec
597 * @param[in] ctx - shared_ptr to an IPMI context struct
598 *
599 * @returns IPMI completion code plus response data
600 * - Device ID (manufacturer defined)
601 * - Device revision[4 bits]; reserved[3 bits]; SDR support[1 bit]
602 * - FW revision major[7 bits] (binary encoded); available[1 bit]
603 * - FW Revision minor (BCD encoded)
604 * - IPMI version (0x02 for IPMI 2.0)
605 * - device support (bitfield of supported options)
606 * - MFG IANA ID (3 bytes)
607 * - product ID (2 bytes)
608 * - AUX info (4 bytes)
609 */
610ipmi::RspType<uint8_t, // Device ID
611 uint8_t, // Device Revision
612 uint8_t, // Firmware Revision Major
613 uint8_t, // Firmware Revision minor
614 uint8_t, // IPMI version
615 uint8_t, // Additional device support
616 uint24_t, // MFG ID
617 uint16_t, // Product ID
618 uint32_t // AUX info
619 >
Willy Tu11d68892022-01-20 10:37:34 -0800620 ipmiAppGetDeviceId([[maybe_unused]] ipmi::Context::ptr ctx)
Chris Austen6caf28b2015-10-13 12:40:40 -0500621{
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600622 int r = -1;
Willy Tu11d68892022-01-20 10:37:34 -0800623 Revision rev = {0, 0, 0, 0};
Vernon Mauery86a50822019-03-25 13:11:36 -0700624 static struct
625 {
626 uint8_t id;
627 uint8_t revision;
628 uint8_t fw[2];
629 uint8_t ipmiVer;
630 uint8_t addnDevSupport;
631 uint24_t manufId;
632 uint16_t prodId;
633 uint32_t aux;
634 } devId;
David Cobbleya1adb072017-11-21 15:58:13 -0800635 static bool dev_id_initialized = false;
JeffLin27a62ec2021-11-24 15:40:33 +0800636 static bool haveBMCVersion = false;
Patrick Venture94930a12019-04-30 10:01:58 -0700637 static bool defaultActivationSetting = true;
David Cobbleya1adb072017-11-21 15:58:13 -0800638 const char* filename = "/usr/share/ipmi-providers/dev_id.json";
Alexander Amelkinba19c182018-09-04 15:49:36 +0300639 constexpr auto ipmiDevIdStateShift = 7;
640 constexpr auto ipmiDevIdFw1Mask = ~(1 << ipmiDevIdStateShift);
JeffLin27a62ec2021-11-24 15:40:33 +0800641 if (!haveBMCVersion || !dev_id_initialized)
David Cobbleya1adb072017-11-21 15:58:13 -0800642 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600643 try
644 {
Vernon Maueryea1c4012019-05-24 13:26:16 -0700645 auto version = getActiveSoftwareVersionInfo(ctx);
Vernon Mauery86a50822019-03-25 13:11:36 -0700646 r = convertVersion(version, rev);
David Cobbleya1adb072017-11-21 15:58:13 -0800647 }
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600648 catch (const std::exception& e)
649 {
650 log<level::ERR>(e.what());
651 }
Nan Liee0cb902016-07-11 15:38:03 +0800652
Patrick Venture0b02be92018-08-31 11:55:55 -0700653 if (r >= 0)
654 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600655 // bit7 identifies if the device is available
656 // 0=normal operation
657 // 1=device firmware, SDR update,
658 // or self-initialization in progress.
Alexander Amelkinba19c182018-09-04 15:49:36 +0300659 // The availability may change in run time, so mask here
660 // and initialize later.
Vernon Mauery86a50822019-03-25 13:11:36 -0700661 devId.fw[0] = rev.major & ipmiDevIdFw1Mask;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600662
663 rev.minor = (rev.minor > 99 ? 99 : rev.minor);
Vernon Mauery86a50822019-03-25 13:11:36 -0700664 devId.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16;
665 std::memcpy(&devId.aux, rev.d, 4);
Brandon Kimc1f5aca2022-03-17 17:54:06 -0700666 haveBMCVersion = true;
David Cobbleya1adb072017-11-21 15:58:13 -0800667 }
JeffLin27a62ec2021-11-24 15:40:33 +0800668 }
669 if (!dev_id_initialized)
670 {
David Cobbleya1adb072017-11-21 15:58:13 -0800671 // IPMI Spec version 2.0
Vernon Mauery86a50822019-03-25 13:11:36 -0700672 devId.ipmiVer = 2;
Adriana Kobylak0e912642016-06-22 16:54:39 -0500673
Vernon Mauery86a50822019-03-25 13:11:36 -0700674 std::ifstream devIdFile(filename);
675 if (devIdFile.is_open())
David Cobbleya1adb072017-11-21 15:58:13 -0800676 {
Vernon Mauery86a50822019-03-25 13:11:36 -0700677 auto data = nlohmann::json::parse(devIdFile, nullptr, false);
David Cobbleya1adb072017-11-21 15:58:13 -0800678 if (!data.is_discarded())
679 {
Vernon Mauery86a50822019-03-25 13:11:36 -0700680 devId.id = data.value("id", 0);
681 devId.revision = data.value("revision", 0);
682 devId.addnDevSupport = data.value("addn_dev_support", 0);
683 devId.manufId = data.value("manuf_id", 0);
684 devId.prodId = data.value("prod_id", 0);
685 devId.aux = data.value("aux", 0);
David Cobbleya1adb072017-11-21 15:58:13 -0800686
Willy Tubfd3a172022-05-31 13:57:54 -0700687 if (data.contains("firmware_revision"))
688 {
689 const auto& firmwareRevision = data.at("firmware_revision");
690 if (firmwareRevision.contains("major"))
691 {
692 firmwareRevision.at("major").get_to(devId.fw[0]);
693 }
694 if (firmwareRevision.contains("minor"))
695 {
696 firmwareRevision.at("minor").get_to(devId.fw[1]);
697 }
698 }
699
Patrick Venture94930a12019-04-30 10:01:58 -0700700 // Set the availablitity of the BMC.
701 defaultActivationSetting = data.value("availability", true);
702
Patrick Venture0b02be92018-08-31 11:55:55 -0700703 // Don't read the file every time if successful
David Cobbleya1adb072017-11-21 15:58:13 -0800704 dev_id_initialized = true;
705 }
706 else
707 {
708 log<level::ERR>("Device ID JSON parser failure");
Vernon Maueryf2587fc2019-04-09 14:28:15 -0700709 return ipmi::responseUnspecifiedError();
David Cobbleya1adb072017-11-21 15:58:13 -0800710 }
711 }
712 else
713 {
714 log<level::ERR>("Device ID file not found");
Vernon Maueryf2587fc2019-04-09 14:28:15 -0700715 return ipmi::responseUnspecifiedError();
Chris Austen7303bdc2016-04-17 11:50:54 -0500716 }
717 }
Chris Austen6caf28b2015-10-13 12:40:40 -0500718
Alexander Amelkinba19c182018-09-04 15:49:36 +0300719 // Set availability to the actual current BMC state
Vernon Mauery86a50822019-03-25 13:11:36 -0700720 devId.fw[0] &= ipmiDevIdFw1Mask;
Patrick Venture94930a12019-04-30 10:01:58 -0700721 if (!getCurrentBmcStateWithFallback(defaultActivationSetting))
Alexander Amelkinba19c182018-09-04 15:49:36 +0300722 {
Vernon Mauery86a50822019-03-25 13:11:36 -0700723 devId.fw[0] |= (1 << ipmiDevIdStateShift);
Alexander Amelkinba19c182018-09-04 15:49:36 +0300724 }
725
Vernon Mauery86a50822019-03-25 13:11:36 -0700726 return ipmi::responseSuccess(
727 devId.id, devId.revision, devId.fw[0], devId.fw[1], devId.ipmiVer,
728 devId.addnDevSupport, devId.manufId, devId.prodId, devId.aux);
Chris Austen6caf28b2015-10-13 12:40:40 -0500729}
730
Vernon Maueryb84a5282019-03-25 13:39:03 -0700731auto ipmiAppGetSelfTestResults() -> ipmi::RspType<uint8_t, uint8_t>
Nan Li41fa24a2016-11-10 20:12:37 +0800732{
Nan Li41fa24a2016-11-10 20:12:37 +0800733 // Byte 2:
734 // 55h - No error.
Gunnar Mills8991dd62017-10-25 17:11:29 -0500735 // 56h - Self Test function not implemented in this controller.
Nan Li41fa24a2016-11-10 20:12:37 +0800736 // 57h - Corrupted or inaccesssible data or devices.
737 // 58h - Fatal hardware error.
738 // FFh - reserved.
739 // all other: Device-specific 'internal failure'.
740 // Byte 3:
741 // For byte 2 = 55h, 56h, FFh: 00h
742 // For byte 2 = 58h, all other: Device-specific
743 // For byte 2 = 57h: self-test error bitfield.
744 // Note: returning 57h does not imply that all test were run.
745 // [7] 1b = Cannot access SEL device.
746 // [6] 1b = Cannot access SDR Repository.
747 // [5] 1b = Cannot access BMC FRU device.
748 // [4] 1b = IPMB signal lines do not respond.
749 // [3] 1b = SDR Repository empty.
750 // [2] 1b = Internal Use Area of BMC FRU corrupted.
751 // [1] 1b = controller update 'boot block' firmware corrupted.
752 // [0] 1b = controller operational firmware corrupted.
Vernon Maueryb84a5282019-03-25 13:39:03 -0700753 constexpr uint8_t notImplemented = 0x56;
754 constexpr uint8_t zero = 0;
755 return ipmi::responseSuccess(notImplemented, zero);
Nan Li41fa24a2016-11-10 20:12:37 +0800756}
757
Vernon Mauery15541322019-03-25 13:33:03 -0700758static constexpr size_t uuidBinaryLength = 16;
759static std::array<uint8_t, uuidBinaryLength> rfc4122ToIpmi(std::string rfc4122)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500760{
Vernon Mauery15541322019-03-25 13:33:03 -0700761 using Argument = xyz::openbmc_project::Common::InvalidArgument;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500762 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Patrick Ventured2117022018-02-06 08:54:37 -0800763 // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte
764 // order
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500765 // Ex: 0x2332fc2c40e66298e511f2782395a361
Vernon Mauery15541322019-03-25 13:33:03 -0700766 constexpr size_t uuidHexLength = (2 * uuidBinaryLength);
767 constexpr size_t uuidRfc4122Length = (uuidHexLength + 4);
768 std::array<uint8_t, uuidBinaryLength> uuid;
769 if (rfc4122.size() == uuidRfc4122Length)
Patrick Venture0b02be92018-08-31 11:55:55 -0700770 {
Vernon Mauery15541322019-03-25 13:33:03 -0700771 rfc4122.erase(std::remove(rfc4122.begin(), rfc4122.end(), '-'),
772 rfc4122.end());
Sergey Solomineb9b8142016-08-23 09:07:28 -0500773 }
Vernon Mauery15541322019-03-25 13:33:03 -0700774 if (rfc4122.size() != uuidHexLength)
vishwa1eaea4f2016-02-26 11:57:40 -0600775 {
Vernon Mauery15541322019-03-25 13:33:03 -0700776 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"),
777 Argument::ARGUMENT_VALUE(rfc4122.c_str()));
vishwa1eaea4f2016-02-26 11:57:40 -0600778 }
Vernon Mauery15541322019-03-25 13:33:03 -0700779 for (size_t ind = 0; ind < uuidHexLength; ind += 2)
vishwa1eaea4f2016-02-26 11:57:40 -0600780 {
Vernon Mauery15541322019-03-25 13:33:03 -0700781 char v[3];
782 v[0] = rfc4122[ind];
783 v[1] = rfc4122[ind + 1];
784 v[2] = 0;
785 size_t err;
786 long b;
787 try
Emily Shafferedb8bb02018-09-27 14:50:15 -0700788 {
Vernon Mauery15541322019-03-25 13:33:03 -0700789 b = std::stoul(v, &err, 16);
Emily Shafferedb8bb02018-09-27 14:50:15 -0700790 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500791 catch (const std::exception& e)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500792 {
Vernon Mauery15541322019-03-25 13:33:03 -0700793 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"),
794 Argument::ARGUMENT_VALUE(rfc4122.c_str()));
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500795 }
Vernon Mauery15541322019-03-25 13:33:03 -0700796 // check that exactly two ascii bytes were converted
797 if (err != 2)
798 {
799 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"),
800 Argument::ARGUMENT_VALUE(rfc4122.c_str()));
801 }
802 uuid[uuidBinaryLength - (ind / 2) - 1] = static_cast<uint8_t>(b);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500803 }
Vernon Mauery15541322019-03-25 13:33:03 -0700804 return uuid;
805}
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500806
Vernon Mauery15541322019-03-25 13:33:03 -0700807auto ipmiAppGetDeviceGuid()
808 -> ipmi::RspType<std::array<uint8_t, uuidBinaryLength>>
809{
810 // return a fixed GUID based on /etc/machine-id
811 // This should match the /redfish/v1/Managers/bmc's UUID data
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500812
Vernon Mauery15541322019-03-25 13:33:03 -0700813 // machine specific application ID (for BMC ID)
814 // generated by systemd-id128 -p new as per man page
815 static constexpr sd_id128_t bmcUuidAppId = SD_ID128_MAKE(
816 e0, e1, 73, 76, 64, 61, 47, da, a5, 0c, d0, cc, 64, 12, 45, 78);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500817
Vernon Mauery15541322019-03-25 13:33:03 -0700818 sd_id128_t bmcUuid;
819 // create the UUID from /etc/machine-id via the systemd API
820 sd_id128_get_machine_app_specific(bmcUuidAppId, &bmcUuid);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500821
Vernon Mauery15541322019-03-25 13:33:03 -0700822 char bmcUuidCstr[SD_ID128_STRING_MAX];
823 std::string systemUuid = sd_id128_to_string(bmcUuid, bmcUuidCstr);
824
825 std::array<uint8_t, uuidBinaryLength> uuid = rfc4122ToIpmi(systemUuid);
826 return ipmi::responseSuccess(uuid);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500827}
Chris Austen6caf28b2015-10-13 12:40:40 -0500828
Vernon Mauerycc99ba42019-03-25 13:40:11 -0700829auto ipmiAppGetBtCapabilities()
830 -> ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t>
vishwabmcba0bd5f2015-09-30 16:50:23 +0530831{
Adriana Kobylak88ad8152016-12-13 10:09:08 -0600832 // Per IPMI 2.0 spec, the input and output buffer size must be the max
833 // buffer size minus one byte to allocate space for the length byte.
Vernon Mauerycc99ba42019-03-25 13:40:11 -0700834 constexpr uint8_t nrOutstanding = 0x01;
835 constexpr uint8_t inputBufferSize = MAX_IPMI_BUFFER - 1;
836 constexpr uint8_t outputBufferSize = MAX_IPMI_BUFFER - 1;
837 constexpr uint8_t transactionTime = 0x0A;
838 constexpr uint8_t nrRetries = 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530839
Vernon Mauerycc99ba42019-03-25 13:40:11 -0700840 return ipmi::responseSuccess(nrOutstanding, inputBufferSize,
841 outputBufferSize, transactionTime, nrRetries);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530842}
843
Vernon Maueryb90a5322019-03-25 13:36:55 -0700844auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>>
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600845{
Vernon Maueryb90a5322019-03-25 13:36:55 -0700846 static constexpr auto bmcInterface =
847 "xyz.openbmc_project.Inventory.Item.Bmc";
848 static constexpr auto uuidInterface = "xyz.openbmc_project.Common.UUID";
849 static constexpr auto uuidProperty = "UUID";
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600850
Vernon Maueryb90a5322019-03-25 13:36:55 -0700851 ipmi::Value propValue;
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600852 try
853 {
854 // Get the Inventory object implementing BMC interface
Vernon Maueryb90a5322019-03-25 13:36:55 -0700855 auto busPtr = getSdBus();
856 auto objectInfo = ipmi::getDbusObject(*busPtr, bmcInterface);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600857
858 // Read UUID property value from bmcObject
859 // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Vernon Maueryb90a5322019-03-25 13:36:55 -0700860 propValue =
861 ipmi::getDbusProperty(*busPtr, objectInfo.second, objectInfo.first,
862 uuidInterface, uuidProperty);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600863 }
864 catch (const InternalFailure& e)
865 {
866 log<level::ERR>("Failed in reading BMC UUID property",
Vernon Maueryb90a5322019-03-25 13:36:55 -0700867 entry("INTERFACE=%s", uuidInterface),
868 entry("PROPERTY=%s", uuidProperty));
869 return ipmi::responseUnspecifiedError();
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600870 }
Vernon Maueryb90a5322019-03-25 13:36:55 -0700871 std::array<uint8_t, 16> uuid;
872 std::string rfc4122Uuid = std::get<std::string>(propValue);
873 try
874 {
875 // convert to IPMI format
876 uuid = rfc4122ToIpmi(rfc4122Uuid);
877 }
878 catch (const InvalidArgument& e)
879 {
880 log<level::ERR>("Failed in parsing BMC UUID property",
881 entry("INTERFACE=%s", uuidInterface),
882 entry("PROPERTY=%s", uuidProperty),
883 entry("VALUE=%s", rfc4122Uuid.c_str()));
884 return ipmi::responseUnspecifiedError();
885 }
886 return ipmi::responseSuccess(uuid);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600887}
888
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +0000889/**
890 * @brief set the session state as teardown
891 *
892 * This function is to set the session state to tear down in progress if the
893 * state is active.
894 *
895 * @param[in] busp - Dbus obj
896 * @param[in] service - service name
897 * @param[in] obj - object path
898 *
899 * @return success completion code if it sets the session state to
900 * tearDownInProgress else return the corresponding error completion code.
901 **/
902uint8_t setSessionState(std::shared_ptr<sdbusplus::asio::connection>& busp,
903 const std::string& service, const std::string& obj)
904{
905 try
906 {
907 uint8_t sessionState = std::get<uint8_t>(ipmi::getDbusProperty(
908 *busp, service, obj, session::sessionIntf, "State"));
909
910 if (sessionState == static_cast<uint8_t>(session::State::active))
911 {
912 ipmi::setDbusProperty(
913 *busp, service, obj, session::sessionIntf, "State",
914 static_cast<uint8_t>(session::State::tearDownInProgress));
915 return ipmi::ccSuccess;
916 }
917 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500918 catch (const std::exception& e)
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +0000919 {
920 log<level::ERR>("Failed in getting session state property",
921 entry("service=%s", service.c_str()),
922 entry("object path=%s", obj.c_str()),
923 entry("interface=%s", session::sessionIntf));
924 return ipmi::ccUnspecifiedError;
925 }
926
927 return ipmi::ccInvalidFieldRequest;
928}
929
930ipmi::RspType<> ipmiAppCloseSession(uint32_t reqSessionId,
931 std::optional<uint8_t> requestSessionHandle)
932{
933 auto busp = getSdBus();
934 uint8_t reqSessionHandle =
935 requestSessionHandle.value_or(session::defaultSessionHandle);
936
937 if (reqSessionId == session::sessionZero &&
938 reqSessionHandle == session::defaultSessionHandle)
939 {
940 return ipmi::response(session::ccInvalidSessionId);
941 }
942
943 if (reqSessionId == session::sessionZero &&
944 reqSessionHandle == session::invalidSessionHandle)
945 {
946 return ipmi::response(session::ccInvalidSessionHandle);
947 }
948
949 if (reqSessionId != session::sessionZero &&
950 reqSessionHandle != session::defaultSessionHandle)
951 {
952 return ipmi::response(ipmi::ccInvalidFieldRequest);
953 }
954
955 try
956 {
957 ipmi::ObjectTree objectTree = ipmi::getAllDbusObjects(
958 *busp, session::sessionManagerRootPath, session::sessionIntf);
959
960 for (auto& objectTreeItr : objectTree)
961 {
962 const std::string obj = objectTreeItr.first;
963
964 if (isSessionObjectMatched(obj, reqSessionId, reqSessionHandle))
965 {
966 auto& serviceMap = objectTreeItr.second;
967
968 // Session id and session handle are unique for each session.
969 // Session id and handler are retrived from the object path and
970 // object path will be unique for each session. Checking if
971 // multiple objects exist with same object path under multiple
972 // services.
973 if (serviceMap.size() != 1)
974 {
975 return ipmi::responseUnspecifiedError();
976 }
977
978 auto itr = serviceMap.begin();
979 const std::string service = itr->first;
980 return ipmi::response(setSessionState(busp, service, obj));
981 }
982 }
983 }
Patrick Williams5d82f472022-07-22 19:26:53 -0500984 catch (const sdbusplus::exception_t& e)
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +0000985 {
986 log<level::ERR>("Failed to fetch object from dbus",
987 entry("INTERFACE=%s", session::sessionIntf),
988 entry("ERRMSG=%s", e.what()));
989 return ipmi::responseUnspecifiedError();
990 }
991
992 return ipmi::responseInvalidFieldRequest();
993}
994
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +0000995uint8_t getTotalSessionCount()
996{
Meera-Kattac1789482021-05-18 09:53:26 +0000997 uint8_t count = 0, ch = 0;
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +0000998
999 while (ch < ipmi::maxIpmiChannels &&
1000 count < session::maxNetworkInstanceSupported)
1001 {
Jayaprakash Mutyala80207e62020-07-04 16:34:15 +00001002 ipmi::ChannelInfo chInfo{};
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001003 ipmi::getChannelInfo(ch, chInfo);
1004 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
1005 ipmi::EChannelMediumType::lan8032)
1006 {
1007 count++;
1008 }
1009 ch++;
1010 }
1011 return count * session::maxSessionCountPerChannel;
1012}
1013
1014/**
1015 * @brief get session info request data.
1016 *
1017 * This function validates the request data and retrive request session id,
1018 * session handle.
1019 *
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301020 * @param[in] ctx - context of current session.
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001021 * @param[in] sessionIndex - request session index
1022 * @param[in] payload - input payload
1023 * @param[in] reqSessionId - unpacked session Id will be asigned
1024 * @param[in] reqSessionHandle - unpacked session handle will be asigned
1025 *
1026 * @return success completion code if request data is valid
1027 * else return the correcponding error completion code.
1028 **/
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301029uint8_t getSessionInfoRequestData(const ipmi::Context::ptr ctx,
1030 const uint8_t sessionIndex,
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001031 ipmi::message::Payload& payload,
1032 uint32_t& reqSessionId,
1033 uint8_t& reqSessionHandle)
1034{
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301035 if ((sessionIndex > session::maxSessionCountPerChannel) &&
1036 (sessionIndex < session::searchSessionByHandle))
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001037 {
1038 return ipmi::ccInvalidFieldRequest;
1039 }
1040
1041 switch (sessionIndex)
1042 {
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301043 case session::searchCurrentSession:
1044
1045 ipmi::ChannelInfo chInfo;
1046 ipmi::getChannelInfo(ctx->channel, chInfo);
1047
1048 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) !=
1049 ipmi::EChannelMediumType::lan8032)
1050 {
1051 return ipmi::ccInvalidFieldRequest;
1052 }
1053
1054 if (!payload.fullyUnpacked())
1055 {
1056 return ipmi::ccReqDataLenInvalid;
1057 }
1058 // Check if current sessionId is 0, sessionId 0 is reserved.
1059 if (ctx->sessionId == session::sessionZero)
1060 {
1061 return session::ccInvalidSessionId;
1062 }
1063 reqSessionId = ctx->sessionId;
1064 break;
1065
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001066 case session::searchSessionByHandle:
1067
1068 if ((payload.unpack(reqSessionHandle)) ||
1069 (!payload.fullyUnpacked()))
1070 {
1071 return ipmi::ccReqDataLenInvalid;
1072 }
1073
1074 if ((reqSessionHandle == session::sessionZero) ||
1075 ((reqSessionHandle & session::multiIntfaceSessionHandleMask) >
1076 session::maxSessionCountPerChannel))
1077 {
1078 return session::ccInvalidSessionHandle;
1079 }
1080 break;
1081
1082 case session::searchSessionById:
1083
1084 if ((payload.unpack(reqSessionId)) || (!payload.fullyUnpacked()))
1085 {
1086 return ipmi::ccReqDataLenInvalid;
1087 }
1088
1089 if (reqSessionId == session::sessionZero)
1090 {
1091 return session::ccInvalidSessionId;
1092 }
1093 break;
1094
1095 default:
1096 if (!payload.fullyUnpacked())
1097 {
1098 return ipmi::ccReqDataLenInvalid;
1099 }
1100 break;
1101 }
1102 return ipmi::ccSuccess;
1103}
1104
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001105uint8_t getSessionState(ipmi::Context::ptr ctx, const std::string& service,
1106 const std::string& objPath, uint8_t& sessionState)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001107{
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001108 boost::system::error_code ec = ipmi::getDbusProperty(
1109 ctx, service, objPath, session::sessionIntf, "State", sessionState);
1110 if (ec)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001111 {
1112 log<level::ERR>("Failed to fetch state property ",
1113 entry("SERVICE=%s", service.c_str()),
1114 entry("OBJECTPATH=%s", objPath.c_str()),
1115 entry("INTERFACE=%s", session::sessionIntf),
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001116 entry("ERRMSG=%s", ec.message().c_str()));
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001117 return ipmi::ccUnspecifiedError;
1118 }
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001119 return ipmi::ccSuccess;
1120}
1121
1122static constexpr uint8_t macAddrLen = 6;
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001123/** Alias SessionDetails - contain the optional information about an
1124 * RMCP+ session.
1125 *
1126 * @param userID - uint6_t session user ID (0-63)
1127 * @param reserved - uint2_t reserved
1128 * @param privilege - uint4_t session privilege (0-5)
1129 * @param reserved - uint4_t reserved
1130 * @param channel - uint4_t session channel number
1131 * @param protocol - uint4_t session protocol
1132 * @param remoteIP - uint32_t remote IP address
1133 * @param macAddr - std::array<uint8_t, 6> mac address
1134 * @param port - uint16_t remote port
1135 */
1136using SessionDetails =
1137 std::tuple<uint2_t, uint6_t, uint4_t, uint4_t, uint4_t, uint4_t, uint32_t,
1138 std::array<uint8_t, macAddrLen>, uint16_t>;
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001139
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001140/** @brief get session details for a given session
1141 *
1142 * @param[in] ctx - ipmi::Context pointer for accessing D-Bus
1143 * @param[in] service - D-Bus service name to fetch details from
1144 * @param[in] objPath - D-Bus object path for session
1145 * @param[out] sessionHandle - return session handle for session
1146 * @param[out] sessionState - return session state for session
1147 * @param[out] details - return a SessionDetails tuple containing other
1148 * session info
1149 * @return - ipmi::Cc success or error code
1150 */
1151ipmi::Cc getSessionDetails(ipmi::Context::ptr ctx, const std::string& service,
1152 const std::string& objPath, uint8_t& sessionHandle,
1153 uint8_t& sessionState, SessionDetails& details)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001154{
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001155 ipmi::PropertyMap sessionProps;
1156 boost::system::error_code ec = ipmi::getAllDbusProperties(
1157 ctx, service, objPath, session::sessionIntf, sessionProps);
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001158
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001159 if (ec)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001160 {
1161 log<level::ERR>("Failed to fetch state property ",
1162 entry("SERVICE=%s", service.c_str()),
1163 entry("OBJECTPATH=%s", objPath.c_str()),
1164 entry("INTERFACE=%s", session::sessionIntf),
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001165 entry("ERRMSG=%s", ec.message().c_str()));
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001166 return ipmi::ccUnspecifiedError;
1167 }
1168
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001169 sessionState = ipmi::mappedVariant<uint8_t>(
1170 sessionProps, "State", static_cast<uint8_t>(session::State::inactive));
1171 if (sessionState == static_cast<uint8_t>(session::State::active))
1172 {
1173 sessionHandle =
1174 ipmi::mappedVariant<uint8_t>(sessionProps, "SessionHandle", 0);
1175 std::get<0>(details) =
1176 ipmi::mappedVariant<uint8_t>(sessionProps, "UserID", 0xff);
1177 // std::get<1>(details) = 0; // (default constructed to 0)
1178 std::get<2>(details) =
1179 ipmi::mappedVariant<uint8_t>(sessionProps, "CurrentPrivilege", 0);
1180 // std::get<3>(details) = 0; // (default constructed to 0)
1181 std::get<4>(details) =
1182 ipmi::mappedVariant<uint8_t>(sessionProps, "ChannelNum", 0xff);
1183 constexpr uint4_t rmcpPlusProtocol = 1;
1184 std::get<5>(details) = rmcpPlusProtocol;
1185 std::get<6>(details) =
1186 ipmi::mappedVariant<uint32_t>(sessionProps, "RemoteIPAddr", 0);
1187 // std::get<7>(details) = {{0}}; // default constructed to all 0
1188 std::get<8>(details) =
1189 ipmi::mappedVariant<uint16_t>(sessionProps, "RemotePort", 0);
1190 }
1191
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001192 return ipmi::ccSuccess;
1193}
1194
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001195ipmi::RspType<uint8_t, // session handle,
1196 uint8_t, // total session count
1197 uint8_t, // active session count
1198 std::optional<SessionDetails>>
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301199 ipmiAppGetSessionInfo(ipmi::Context::ptr ctx, uint8_t sessionIndex,
1200 ipmi::message::Payload& payload)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001201{
1202 uint32_t reqSessionId = 0;
1203 uint8_t reqSessionHandle = session::defaultSessionHandle;
1204 // initializing state to 0xff as 0 represents state as inactive.
1205 uint8_t state = 0xFF;
1206
1207 uint8_t completionCode = getSessionInfoRequestData(
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301208 ctx, sessionIndex, payload, reqSessionId, reqSessionHandle);
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001209
1210 if (completionCode)
1211 {
1212 return ipmi::response(completionCode);
1213 }
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001214 ipmi::ObjectTree objectTree;
1215 boost::system::error_code ec = ipmi::getAllDbusObjects(
1216 ctx, session::sessionManagerRootPath, session::sessionIntf, objectTree);
1217 if (ec)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001218 {
1219 log<level::ERR>("Failed to fetch object from dbus",
1220 entry("INTERFACE=%s", session::sessionIntf),
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001221 entry("ERRMSG=%s", ec.message().c_str()));
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001222 return ipmi::responseUnspecifiedError();
1223 }
1224
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001225 uint8_t totalSessionCount = getTotalSessionCount();
1226 uint8_t activeSessionCount = 0;
1227 uint8_t sessionHandle = session::defaultSessionHandle;
1228 std::optional<SessionDetails> maybeDetails;
1229 uint8_t index = 0;
1230 for (auto& objectTreeItr : objectTree)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001231 {
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001232 uint32_t sessionId = 0;
1233 std::string objectPath = objectTreeItr.first;
1234
1235 if (!parseCloseSessionInputPayload(objectPath, sessionId,
1236 sessionHandle))
1237 {
1238 continue;
1239 }
1240 index++;
1241 auto& serviceMap = objectTreeItr.second;
1242 auto itr = serviceMap.begin();
1243
1244 if (serviceMap.size() != 1)
1245 {
1246 return ipmi::responseUnspecifiedError();
1247 }
1248
1249 std::string service = itr->first;
1250 uint8_t sessionState = 0;
1251 completionCode =
1252 getSessionState(ctx, service, objectPath, sessionState);
1253 if (completionCode)
1254 {
1255 return ipmi::response(completionCode);
1256 }
1257
1258 if (sessionState == static_cast<uint8_t>(session::State::active))
1259 {
1260 activeSessionCount++;
1261 }
1262
1263 if (index != sessionIndex && reqSessionId != sessionId &&
1264 reqSessionHandle != sessionHandle)
1265 {
1266 continue;
1267 }
1268
1269 SessionDetails details{};
1270 completionCode = getSessionDetails(ctx, service, objectPath,
1271 sessionHandle, state, details);
1272
1273 if (completionCode)
1274 {
1275 return ipmi::response(completionCode);
1276 }
1277 maybeDetails = std::move(details);
Brian Ma61880882022-07-15 09:34:07 +08001278 break;
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001279 }
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001280
1281 if (state == static_cast<uint8_t>(session::State::active) ||
1282 state == static_cast<uint8_t>(session::State::tearDownInProgress))
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001283 {
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001284 return ipmi::responseSuccess(sessionHandle, totalSessionCount,
1285 activeSessionCount, maybeDetails);
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001286 }
1287
1288 return ipmi::responseInvalidFieldRequest();
1289}
1290
Xo Wangf542e8b2017-08-09 15:34:16 -07001291static std::unique_ptr<SysInfoParamStore> sysInfoParamStore;
1292
Xo Wang87651332017-08-11 10:17:59 -07001293static std::string sysInfoReadSystemName()
1294{
1295 // Use the BMC hostname as the "System Name."
1296 char hostname[HOST_NAME_MAX + 1] = {};
1297 if (gethostname(hostname, HOST_NAME_MAX) != 0)
1298 {
1299 perror("System info parameter: system name");
1300 }
1301 return hostname;
1302}
1303
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001304static constexpr uint8_t paramRevision = 0x11;
1305static constexpr size_t configParameterLength = 16;
Xo Wangf542e8b2017-08-09 15:34:16 -07001306
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001307static constexpr size_t smallChunkSize = 14;
1308static constexpr size_t fullChunkSize = 16;
Jia, chunhui449f2162019-09-11 16:51:51 +08001309static constexpr uint8_t progressMask = 0x3;
Xo Wangf542e8b2017-08-09 15:34:16 -07001310
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001311static constexpr uint8_t setComplete = 0x0;
1312static constexpr uint8_t setInProgress = 0x1;
1313static constexpr uint8_t commitWrite = 0x2;
1314static uint8_t transferStatus = setComplete;
1315
Jia, chunhui449f2162019-09-11 16:51:51 +08001316static constexpr uint8_t configDataOverhead = 2;
1317
1318// For EFI based system, 256 bytes is recommended.
1319static constexpr size_t maxBytesPerParameter = 256;
1320
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001321namespace ipmi
1322{
1323constexpr Cc ccParmNotSupported = 0x80;
Jia, chunhui449f2162019-09-11 16:51:51 +08001324constexpr Cc ccSetInProgressActive = 0x81;
1325constexpr Cc ccSystemInfoParameterSetReadOnly = 0x82;
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001326
1327static inline auto responseParmNotSupported()
1328{
1329 return response(ccParmNotSupported);
Xo Wangf542e8b2017-08-09 15:34:16 -07001330}
Jia, chunhui449f2162019-09-11 16:51:51 +08001331static inline auto responseSetInProgressActive()
1332{
1333 return response(ccSetInProgressActive);
1334}
1335static inline auto responseSystemInfoParameterSetReadOnly()
1336{
1337 return response(ccSystemInfoParameterSetReadOnly);
1338}
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001339} // namespace ipmi
Xo Wangf542e8b2017-08-09 15:34:16 -07001340
Jia, chunhui449f2162019-09-11 16:51:51 +08001341ipmi::RspType<uint8_t, // Parameter revision
1342 std::optional<uint8_t>, // data1 / setSelector / ProgressStatus
1343 std::optional<std::vector<uint8_t>>> // data2-17
jayaprakash Mutyalac2566a92020-04-23 21:18:35 +00001344 ipmiAppGetSystemInfo(uint7_t reserved, bool getRevision,
1345 uint8_t paramSelector, uint8_t setSelector,
1346 uint8_t BlockSelector)
Xo Wangf542e8b2017-08-09 15:34:16 -07001347{
Snehalatha Va5ae7722020-05-02 18:18:57 +00001348 if (reserved || (paramSelector >= invalidParamSelectorStart &&
1349 paramSelector <= invalidParamSelectorEnd))
jayaprakash Mutyalac2566a92020-04-23 21:18:35 +00001350 {
1351 return ipmi::responseInvalidFieldRequest();
1352 }
Snehalatha Va5ae7722020-05-02 18:18:57 +00001353 if ((paramSelector >= oemCmdStart) && (paramSelector <= oemCmdEnd))
1354 {
1355 return ipmi::responseParmNotSupported();
1356 }
jayaprakash Mutyalac2566a92020-04-23 21:18:35 +00001357 if (getRevision)
Xo Wangf542e8b2017-08-09 15:34:16 -07001358 {
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001359 return ipmi::responseSuccess(paramRevision, std::nullopt, std::nullopt);
Xo Wangf542e8b2017-08-09 15:34:16 -07001360 }
1361
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001362 if (paramSelector == 0)
Xo Wangf542e8b2017-08-09 15:34:16 -07001363 {
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001364 return ipmi::responseSuccess(paramRevision, transferStatus,
1365 std::nullopt);
Xo Wangf542e8b2017-08-09 15:34:16 -07001366 }
1367
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001368 if (BlockSelector != 0) // 00h if parameter does not require a block number
Xo Wangf542e8b2017-08-09 15:34:16 -07001369 {
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001370 return ipmi::responseParmNotSupported();
Xo Wangf542e8b2017-08-09 15:34:16 -07001371 }
1372
1373 if (sysInfoParamStore == nullptr)
1374 {
1375 sysInfoParamStore = std::make_unique<SysInfoParamStore>();
Xo Wang87651332017-08-11 10:17:59 -07001376 sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME,
1377 sysInfoReadSystemName);
Xo Wangf542e8b2017-08-09 15:34:16 -07001378 }
1379
1380 // Parameters other than Set In Progress are assumed to be strings.
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001381 std::tuple<bool, std::string> ret =
1382 sysInfoParamStore->lookup(paramSelector);
1383 bool found = std::get<0>(ret);
Xo Wangf542e8b2017-08-09 15:34:16 -07001384 if (!found)
1385 {
Snehalatha Va5ae7722020-05-02 18:18:57 +00001386 return ipmi::responseSensorInvalid();
Xo Wangf542e8b2017-08-09 15:34:16 -07001387 }
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001388 std::string& paramString = std::get<1>(ret);
Jia, chunhui449f2162019-09-11 16:51:51 +08001389 std::vector<uint8_t> configData;
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001390 size_t count = 0;
1391 if (setSelector == 0)
Jia, chunhui449f2162019-09-11 16:51:51 +08001392 { // First chunk has only 14 bytes.
1393 configData.emplace_back(0); // encoding
1394 configData.emplace_back(paramString.length()); // string length
1395 count = std::min(paramString.length(), smallChunkSize);
1396 configData.resize(count + configDataOverhead);
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001397 std::copy_n(paramString.begin(), count,
Snehalatha Va5ae7722020-05-02 18:18:57 +00001398 configData.begin() + configDataOverhead); // 14 bytes chunk
1399
1400 // Append zero's to remaining bytes
1401 if (configData.size() < configParameterLength)
1402 {
1403 std::fill_n(std::back_inserter(configData),
1404 configParameterLength - configData.size(), 0x00);
1405 }
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001406 }
1407 else
Xo Wangf542e8b2017-08-09 15:34:16 -07001408 {
Jia, chunhui449f2162019-09-11 16:51:51 +08001409 size_t offset = (setSelector * fullChunkSize) - configDataOverhead;
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001410 if (offset >= paramString.length())
1411 {
1412 return ipmi::responseParmOutOfRange();
1413 }
Jia, chunhui449f2162019-09-11 16:51:51 +08001414 count = std::min(paramString.length() - offset, fullChunkSize);
1415 configData.resize(count);
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001416 std::copy_n(paramString.begin() + offset, count,
1417 configData.begin()); // 16 bytes chunk
Xo Wangf542e8b2017-08-09 15:34:16 -07001418 }
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001419 return ipmi::responseSuccess(paramRevision, setSelector, configData);
Xo Wangf542e8b2017-08-09 15:34:16 -07001420}
1421
Jia, chunhui449f2162019-09-11 16:51:51 +08001422ipmi::RspType<> ipmiAppSetSystemInfo(uint8_t paramSelector, uint8_t data1,
1423 std::vector<uint8_t> configData)
1424{
jayaprakash Mutyala3c5e4132020-04-27 23:00:05 +00001425 if (paramSelector >= invalidParamSelectorStart &&
1426 paramSelector <= invalidParamSelectorEnd)
1427 {
1428 return ipmi::responseInvalidFieldRequest();
1429 }
1430 if ((paramSelector >= oemCmdStart) && (paramSelector <= oemCmdEnd))
1431 {
1432 return ipmi::responseParmNotSupported();
1433 }
1434
Jia, chunhui449f2162019-09-11 16:51:51 +08001435 if (paramSelector == 0)
1436 {
1437 // attempt to set the 'set in progress' value (in parameter #0)
1438 // when not in the set complete state.
1439 if ((transferStatus != setComplete) && (data1 == setInProgress))
1440 {
1441 return ipmi::responseSetInProgressActive();
1442 }
1443 // only following 2 states are supported
1444 if (data1 > setInProgress)
1445 {
1446 phosphor::logging::log<phosphor::logging::level::ERR>(
1447 "illegal SetInProgress status");
1448 return ipmi::responseInvalidFieldRequest();
1449 }
1450
1451 transferStatus = data1 & progressMask;
1452 return ipmi::responseSuccess();
1453 }
1454
1455 if (configData.size() > configParameterLength)
1456 {
1457 return ipmi::responseInvalidFieldRequest();
1458 }
1459
jayaprakash Mutyala3c5e4132020-04-27 23:00:05 +00001460 // Append zero's to remaining bytes
1461 if (configData.size() < configParameterLength)
1462 {
1463 fill_n(back_inserter(configData),
1464 (configParameterLength - configData.size()), 0x00);
1465 }
1466
Jia, chunhui449f2162019-09-11 16:51:51 +08001467 if (!sysInfoParamStore)
1468 {
1469 sysInfoParamStore = std::make_unique<SysInfoParamStore>();
1470 sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME,
1471 sysInfoReadSystemName);
1472 }
1473
1474 // lookup
1475 std::tuple<bool, std::string> ret =
1476 sysInfoParamStore->lookup(paramSelector);
1477 bool found = std::get<0>(ret);
1478 std::string& paramString = std::get<1>(ret);
1479 if (!found)
1480 {
1481 // parameter does not exist. Init new
1482 paramString = "";
1483 }
1484
1485 uint8_t setSelector = data1;
1486 size_t count = 0;
1487 if (setSelector == 0) // First chunk has only 14 bytes.
1488 {
1489 size_t stringLen = configData.at(1); // string length
1490 // maxBytesPerParamter is 256. It will always be greater than stringLen
1491 // (unit8_t) if maxBytes changes in future, then following line is
1492 // needed.
1493 // stringLen = std::min(stringLen, maxBytesPerParameter);
1494 count = std::min(stringLen, smallChunkSize);
1495 count = std::min(count, configData.size());
1496 paramString.resize(stringLen); // reserve space
1497 std::copy_n(configData.begin() + configDataOverhead, count,
1498 paramString.begin());
1499 }
1500 else
1501 {
1502 size_t offset = (setSelector * fullChunkSize) - configDataOverhead;
1503 if (offset >= paramString.length())
1504 {
1505 return ipmi::responseParmOutOfRange();
1506 }
1507 count = std::min(paramString.length() - offset, configData.size());
1508 std::copy_n(configData.begin(), count, paramString.begin() + offset);
1509 }
1510 sysInfoParamStore->update(paramSelector, paramString);
1511 return ipmi::responseSuccess();
1512}
1513
Yong Libd0503a2019-08-22 17:17:17 +08001514#ifdef ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301515inline std::vector<uint8_t> convertStringToData(const std::string& command)
1516{
1517 std::istringstream iss(command);
1518 std::string token;
1519 std::vector<uint8_t> dataValue;
1520 while (std::getline(iss, token, ' '))
1521 {
1522 dataValue.emplace_back(
1523 static_cast<uint8_t>(std::stoul(token, nullptr, base_16)));
1524 }
1525 return dataValue;
1526}
1527
1528static bool populateI2CMasterWRWhitelist()
1529{
1530 nlohmann::json data = nullptr;
1531 std::ifstream jsonFile(i2cMasterWRWhitelistFile);
1532
1533 if (!jsonFile.good())
1534 {
1535 log<level::WARNING>("i2c white list file not found!",
1536 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile));
1537 return false;
1538 }
1539
1540 try
1541 {
1542 data = nlohmann::json::parse(jsonFile, nullptr, false);
1543 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001544 catch (const nlohmann::json::parse_error& e)
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301545 {
1546 log<level::ERR>("Corrupted i2c white list config file",
1547 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile),
1548 entry("MSG: %s", e.what()));
1549 return false;
1550 }
1551
1552 try
1553 {
1554 // Example JSON Structure format
1555 // "filters": [
1556 // {
1557 // "Description": "Allow full read - ignore first byte write value
1558 // for 0x40 to 0x4F",
1559 // "busId": "0x01",
1560 // "slaveAddr": "0x40",
1561 // "slaveAddrMask": "0x0F",
1562 // "command": "0x00",
1563 // "commandMask": "0xFF"
1564 // },
1565 // {
1566 // "Description": "Allow full read - first byte match 0x05 and
1567 // ignore second byte",
1568 // "busId": "0x01",
1569 // "slaveAddr": "0x57",
1570 // "slaveAddrMask": "0x00",
1571 // "command": "0x05 0x00",
1572 // "commandMask": "0x00 0xFF"
1573 // },]
1574
1575 nlohmann::json filters = data[filtersStr].get<nlohmann::json>();
1576 std::vector<i2cMasterWRWhitelist>& whitelist = getWRWhitelist();
1577 for (const auto& it : filters.items())
1578 {
1579 nlohmann::json filter = it.value();
1580 if (filter.is_null())
1581 {
1582 log<level::ERR>(
1583 "Corrupted I2C master write read whitelist config file",
1584 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile));
1585 return false;
1586 }
1587 const std::vector<uint8_t>& writeData =
1588 convertStringToData(filter[cmdStr].get<std::string>());
1589 const std::vector<uint8_t>& writeDataMask =
1590 convertStringToData(filter[cmdMaskStr].get<std::string>());
1591 if (writeDataMask.size() != writeData.size())
1592 {
1593 log<level::ERR>("I2C master write read whitelist filter "
1594 "mismatch for command & mask size");
1595 return false;
1596 }
1597 whitelist.push_back(
1598 {static_cast<uint8_t>(std::stoul(
1599 filter[busIdStr].get<std::string>(), nullptr, base_16)),
1600 static_cast<uint8_t>(
1601 std::stoul(filter[slaveAddrStr].get<std::string>(),
1602 nullptr, base_16)),
1603 static_cast<uint8_t>(
1604 std::stoul(filter[slaveAddrMaskStr].get<std::string>(),
1605 nullptr, base_16)),
1606 writeData, writeDataMask});
1607 }
1608 if (whitelist.size() != filters.size())
1609 {
1610 log<level::ERR>(
1611 "I2C master write read whitelist filter size mismatch");
1612 return false;
1613 }
1614 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001615 catch (const std::exception& e)
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301616 {
1617 log<level::ERR>("I2C master write read whitelist unexpected exception",
1618 entry("ERROR=%s", e.what()));
1619 return false;
1620 }
1621 return true;
1622}
1623
1624static inline bool isWriteDataWhitelisted(const std::vector<uint8_t>& data,
1625 const std::vector<uint8_t>& dataMask,
1626 const std::vector<uint8_t>& writeData)
1627{
1628 std::vector<uint8_t> processedDataBuf(data.size());
1629 std::vector<uint8_t> processedReqBuf(dataMask.size());
1630 std::transform(writeData.begin(), writeData.end(), dataMask.begin(),
1631 processedReqBuf.begin(), std::bit_or<uint8_t>());
1632 std::transform(data.begin(), data.end(), dataMask.begin(),
1633 processedDataBuf.begin(), std::bit_or<uint8_t>());
1634
1635 return (processedDataBuf == processedReqBuf);
1636}
1637
1638static bool isCmdWhitelisted(uint8_t busId, uint8_t slaveAddr,
1639 std::vector<uint8_t>& writeData)
1640{
1641 std::vector<i2cMasterWRWhitelist>& whiteList = getWRWhitelist();
1642 for (const auto& wlEntry : whiteList)
1643 {
1644 if ((busId == wlEntry.busId) &&
1645 ((slaveAddr | wlEntry.slaveAddrMask) ==
1646 (wlEntry.slaveAddr | wlEntry.slaveAddrMask)))
1647 {
1648 const std::vector<uint8_t>& dataMask = wlEntry.dataMask;
1649 // Skip as no-match, if requested write data is more than the
1650 // write data mask size
1651 if (writeData.size() > dataMask.size())
1652 {
1653 continue;
1654 }
1655 if (isWriteDataWhitelisted(wlEntry.data, dataMask, writeData))
1656 {
1657 return true;
1658 }
1659 }
1660 }
1661 return false;
1662}
Yong Libd0503a2019-08-22 17:17:17 +08001663#else
1664static bool populateI2CMasterWRWhitelist()
1665{
1666 log<level::INFO>(
1667 "I2C_WHITELIST_CHECK is disabled, do not populate whitelist");
1668 return true;
1669}
1670#endif // ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301671
1672/** @brief implements master write read IPMI command which can be used for
1673 * low-level I2C/SMBus write, read or write-read access
1674 * @param isPrivateBus -to indicate private bus usage
1675 * @param busId - bus id
1676 * @param channelNum - channel number
1677 * @param reserved - skip 1 bit
1678 * @param slaveAddr - slave address
1679 * @param read count - number of bytes to be read
1680 * @param writeData - data to be written
1681 *
1682 * @returns IPMI completion code plus response data
1683 * - readData - i2c response data
1684 */
1685ipmi::RspType<std::vector<uint8_t>>
Willy Tu11d68892022-01-20 10:37:34 -08001686 ipmiMasterWriteRead([[maybe_unused]] bool isPrivateBus, uint3_t busId,
1687 [[maybe_unused]] uint4_t channelNum, bool reserved,
1688 uint7_t slaveAddr, uint8_t readCount,
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301689 std::vector<uint8_t> writeData)
1690{
Jayaprakash Mutyalac2af98b2021-09-14 09:19:11 +00001691 if (reserved)
1692 {
1693 return ipmi::responseInvalidFieldRequest();
1694 }
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301695 if (readCount > maxIPMIWriteReadSize)
1696 {
1697 log<level::ERR>("Master write read command: Read count exceeds limit");
1698 return ipmi::responseParmOutOfRange();
1699 }
1700 const size_t writeCount = writeData.size();
1701 if (!readCount && !writeCount)
1702 {
1703 log<level::ERR>("Master write read command: Read & write count are 0");
1704 return ipmi::responseInvalidFieldRequest();
1705 }
Yong Libd0503a2019-08-22 17:17:17 +08001706#ifdef ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301707 if (!isCmdWhitelisted(static_cast<uint8_t>(busId),
1708 static_cast<uint8_t>(slaveAddr), writeData))
1709 {
1710 log<level::ERR>("Master write read request blocked!",
1711 entry("BUS=%d", static_cast<uint8_t>(busId)),
1712 entry("ADDR=0x%x", static_cast<uint8_t>(slaveAddr)));
1713 return ipmi::responseInvalidFieldRequest();
1714 }
Yong Libd0503a2019-08-22 17:17:17 +08001715#endif // ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301716 std::vector<uint8_t> readBuf(readCount);
1717 std::string i2cBus =
1718 "/dev/i2c-" + std::to_string(static_cast<uint8_t>(busId));
1719
Yong Li7dc4ac02019-08-23 17:44:32 +08001720 ipmi::Cc ret = ipmi::i2cWriteRead(i2cBus, static_cast<uint8_t>(slaveAddr),
1721 writeData, readBuf);
1722 if (ret != ipmi::ccSuccess)
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301723 {
Yong Li7dc4ac02019-08-23 17:44:32 +08001724 return ipmi::response(ret);
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301725 }
1726 return ipmi::responseSuccess(readBuf);
1727}
1728
Chris Austen6caf28b2015-10-13 12:40:40 -05001729void register_netfn_app_functions()
vishwabmcba0bd5f2015-09-30 16:50:23 +05301730{
Vernon Mauery86a50822019-03-25 13:11:36 -07001731 // <Get Device ID>
1732 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1733 ipmi::app::cmdGetDeviceId, ipmi::Privilege::User,
1734 ipmiAppGetDeviceId);
1735
Tom05732372016-09-06 17:21:23 +05301736 // <Get BT Interface Capabilities>
Vernon Mauerycc99ba42019-03-25 13:40:11 -07001737 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1738 ipmi::app::cmdGetBtIfaceCapabilities,
1739 ipmi::Privilege::User, ipmiAppGetBtCapabilities);
Chris Austen6caf28b2015-10-13 12:40:40 -05001740
Tom05732372016-09-06 17:21:23 +05301741 // <Reset Watchdog Timer>
Vernon Mauery11df4f62019-03-25 14:17:54 -07001742 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1743 ipmi::app::cmdResetWatchdogTimer,
1744 ipmi::Privilege::Operator, ipmiAppResetWatchdogTimer);
Chris Austen6caf28b2015-10-13 12:40:40 -05001745
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001746 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
AppaRao Puli5a98ea62019-11-10 21:15:02 +05301747 ipmi::app::cmdGetSessionInfo, ipmi::Privilege::User,
1748 ipmiAppGetSessionInfo);
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001749
Tom05732372016-09-06 17:21:23 +05301750 // <Set Watchdog Timer>
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +00001751 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1752 ipmi::app::cmdSetWatchdogTimer,
1753 ipmi::Privilege::Operator, ipmiSetWatchdogTimer);
Chris Austen6caf28b2015-10-13 12:40:40 -05001754
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +00001755 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1756 ipmi::app::cmdCloseSession, ipmi::Privilege::Callback,
1757 ipmiAppCloseSession);
1758
William A. Kennington III73f44512018-02-09 15:28:46 -08001759 // <Get Watchdog Timer>
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +00001760 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
AppaRao Puli5a98ea62019-11-10 21:15:02 +05301761 ipmi::app::cmdGetWatchdogTimer, ipmi::Privilege::User,
1762 ipmiGetWatchdogTimer);
William A. Kennington III73f44512018-02-09 15:28:46 -08001763
Tom05732372016-09-06 17:21:23 +05301764 // <Get Self Test Results>
Vernon Maueryb84a5282019-03-25 13:39:03 -07001765 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1766 ipmi::app::cmdGetSelfTestResults,
1767 ipmi::Privilege::User, ipmiAppGetSelfTestResults);
Nan Li41fa24a2016-11-10 20:12:37 +08001768
Tom05732372016-09-06 17:21:23 +05301769 // <Get Device GUID>
Vernon Mauery15541322019-03-25 13:33:03 -07001770 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1771 ipmi::app::cmdGetDeviceGuid, ipmi::Privilege::User,
1772 ipmiAppGetDeviceGuid);
Adriana Kobylakd100ee52015-10-20 17:02:37 -05001773
Tom05732372016-09-06 17:21:23 +05301774 // <Set ACPI Power State>
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +00001775 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1776 ipmi::app::cmdSetAcpiPowerState,
1777 ipmi::Privilege::Admin, ipmiSetAcpiPowerState);
Yong Li18d77262018-10-09 01:59:45 +08001778 // <Get ACPI Power State>
Deepak Kumar Sahu4e6d2572019-05-07 19:53:37 +00001779 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1780 ipmi::app::cmdGetAcpiPowerState,
AppaRao Puli5a98ea62019-11-10 21:15:02 +05301781 ipmi::Privilege::User, ipmiGetAcpiPowerState);
Yong Li18d77262018-10-09 01:59:45 +08001782
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301783 // Note: For security reason, this command will be registered only when
1784 // there are proper I2C Master write read whitelist
1785 if (populateI2CMasterWRWhitelist())
1786 {
1787 // Note: For security reasons, registering master write read as admin
1788 // privilege command, even though IPMI 2.0 specification allows it as
1789 // operator privilege.
1790 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1791 ipmi::app::cmdMasterWriteRead,
1792 ipmi::Privilege::Admin, ipmiMasterWriteRead);
1793 }
1794
Marri Devender Rao5e007a52018-01-08 06:18:36 -06001795 // <Get System GUID Command>
Vernon Maueryb90a5322019-03-25 13:36:55 -07001796 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1797 ipmi::app::cmdGetSystemGuid, ipmi::Privilege::User,
1798 ipmiAppGetSystemGuid);
Tom Joseph7cbe2282018-03-21 21:17:33 +05301799
1800 // <Get Channel Cipher Suites Command>
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +00001801 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1802 ipmi::app::cmdGetChannelCipherSuites,
Vernon Mauery79b4eea2019-11-07 09:51:39 -08001803 ipmi::Privilege::None, getChannelCipherSuites);
Vernon Maueryd2a57de2019-03-25 12:45:28 -07001804
Xo Wangf542e8b2017-08-09 15:34:16 -07001805 // <Get System Info Command>
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001806 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1807 ipmi::app::cmdGetSystemInfoParameters,
1808 ipmi::Privilege::User, ipmiAppGetSystemInfo);
Jia, chunhui449f2162019-09-11 16:51:51 +08001809 // <Set System Info Command>
1810 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1811 ipmi::app::cmdSetSystemInfoParameters,
1812 ipmi::Privilege::Admin, ipmiAppSetSystemInfo);
vishwabmcba0bd5f2015-09-30 16:50:23 +05301813 return;
1814}