blob: d0d77f8665905ccb193201e8ff433284b2c358c1 [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 uuidInterface = "xyz.openbmc_project.Common.UUID";
847 static constexpr auto uuidProperty = "UUID";
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600848
Vernon Maueryb90a5322019-03-25 13:36:55 -0700849 ipmi::Value propValue;
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600850 try
851 {
852 // Get the Inventory object implementing BMC interface
Vernon Maueryb90a5322019-03-25 13:36:55 -0700853 auto busPtr = getSdBus();
Hieu Huynh45aed692022-10-12 10:58:26 +0000854 auto objectInfo = ipmi::getDbusObject(*busPtr, uuidInterface);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600855
856 // Read UUID property value from bmcObject
857 // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Vernon Maueryb90a5322019-03-25 13:36:55 -0700858 propValue =
859 ipmi::getDbusProperty(*busPtr, objectInfo.second, objectInfo.first,
860 uuidInterface, uuidProperty);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600861 }
862 catch (const InternalFailure& e)
863 {
864 log<level::ERR>("Failed in reading BMC UUID property",
Vernon Maueryb90a5322019-03-25 13:36:55 -0700865 entry("INTERFACE=%s", uuidInterface),
866 entry("PROPERTY=%s", uuidProperty));
867 return ipmi::responseUnspecifiedError();
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600868 }
Vernon Maueryb90a5322019-03-25 13:36:55 -0700869 std::array<uint8_t, 16> uuid;
870 std::string rfc4122Uuid = std::get<std::string>(propValue);
871 try
872 {
873 // convert to IPMI format
874 uuid = rfc4122ToIpmi(rfc4122Uuid);
875 }
876 catch (const InvalidArgument& e)
877 {
878 log<level::ERR>("Failed in parsing BMC UUID property",
879 entry("INTERFACE=%s", uuidInterface),
880 entry("PROPERTY=%s", uuidProperty),
881 entry("VALUE=%s", rfc4122Uuid.c_str()));
882 return ipmi::responseUnspecifiedError();
883 }
884 return ipmi::responseSuccess(uuid);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600885}
886
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +0000887/**
888 * @brief set the session state as teardown
889 *
890 * This function is to set the session state to tear down in progress if the
891 * state is active.
892 *
893 * @param[in] busp - Dbus obj
894 * @param[in] service - service name
895 * @param[in] obj - object path
896 *
897 * @return success completion code if it sets the session state to
898 * tearDownInProgress else return the corresponding error completion code.
899 **/
900uint8_t setSessionState(std::shared_ptr<sdbusplus::asio::connection>& busp,
901 const std::string& service, const std::string& obj)
902{
903 try
904 {
905 uint8_t sessionState = std::get<uint8_t>(ipmi::getDbusProperty(
906 *busp, service, obj, session::sessionIntf, "State"));
907
908 if (sessionState == static_cast<uint8_t>(session::State::active))
909 {
910 ipmi::setDbusProperty(
911 *busp, service, obj, session::sessionIntf, "State",
912 static_cast<uint8_t>(session::State::tearDownInProgress));
913 return ipmi::ccSuccess;
914 }
915 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500916 catch (const std::exception& e)
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +0000917 {
918 log<level::ERR>("Failed in getting session state property",
919 entry("service=%s", service.c_str()),
920 entry("object path=%s", obj.c_str()),
921 entry("interface=%s", session::sessionIntf));
922 return ipmi::ccUnspecifiedError;
923 }
924
925 return ipmi::ccInvalidFieldRequest;
926}
927
928ipmi::RspType<> ipmiAppCloseSession(uint32_t reqSessionId,
929 std::optional<uint8_t> requestSessionHandle)
930{
931 auto busp = getSdBus();
932 uint8_t reqSessionHandle =
933 requestSessionHandle.value_or(session::defaultSessionHandle);
934
935 if (reqSessionId == session::sessionZero &&
936 reqSessionHandle == session::defaultSessionHandle)
937 {
938 return ipmi::response(session::ccInvalidSessionId);
939 }
940
941 if (reqSessionId == session::sessionZero &&
942 reqSessionHandle == session::invalidSessionHandle)
943 {
944 return ipmi::response(session::ccInvalidSessionHandle);
945 }
946
947 if (reqSessionId != session::sessionZero &&
948 reqSessionHandle != session::defaultSessionHandle)
949 {
950 return ipmi::response(ipmi::ccInvalidFieldRequest);
951 }
952
953 try
954 {
955 ipmi::ObjectTree objectTree = ipmi::getAllDbusObjects(
956 *busp, session::sessionManagerRootPath, session::sessionIntf);
957
958 for (auto& objectTreeItr : objectTree)
959 {
960 const std::string obj = objectTreeItr.first;
961
962 if (isSessionObjectMatched(obj, reqSessionId, reqSessionHandle))
963 {
964 auto& serviceMap = objectTreeItr.second;
965
966 // Session id and session handle are unique for each session.
967 // Session id and handler are retrived from the object path and
968 // object path will be unique for each session. Checking if
969 // multiple objects exist with same object path under multiple
970 // services.
971 if (serviceMap.size() != 1)
972 {
973 return ipmi::responseUnspecifiedError();
974 }
975
976 auto itr = serviceMap.begin();
977 const std::string service = itr->first;
978 return ipmi::response(setSessionState(busp, service, obj));
979 }
980 }
981 }
Patrick Williams5d82f472022-07-22 19:26:53 -0500982 catch (const sdbusplus::exception_t& e)
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +0000983 {
984 log<level::ERR>("Failed to fetch object from dbus",
985 entry("INTERFACE=%s", session::sessionIntf),
986 entry("ERRMSG=%s", e.what()));
987 return ipmi::responseUnspecifiedError();
988 }
989
990 return ipmi::responseInvalidFieldRequest();
991}
992
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +0000993uint8_t getTotalSessionCount()
994{
Meera-Kattac1789482021-05-18 09:53:26 +0000995 uint8_t count = 0, ch = 0;
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +0000996
997 while (ch < ipmi::maxIpmiChannels &&
998 count < session::maxNetworkInstanceSupported)
999 {
Jayaprakash Mutyala80207e62020-07-04 16:34:15 +00001000 ipmi::ChannelInfo chInfo{};
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001001 ipmi::getChannelInfo(ch, chInfo);
1002 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
1003 ipmi::EChannelMediumType::lan8032)
1004 {
1005 count++;
1006 }
1007 ch++;
1008 }
1009 return count * session::maxSessionCountPerChannel;
1010}
1011
1012/**
1013 * @brief get session info request data.
1014 *
1015 * This function validates the request data and retrive request session id,
1016 * session handle.
1017 *
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301018 * @param[in] ctx - context of current session.
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001019 * @param[in] sessionIndex - request session index
1020 * @param[in] payload - input payload
1021 * @param[in] reqSessionId - unpacked session Id will be asigned
1022 * @param[in] reqSessionHandle - unpacked session handle will be asigned
1023 *
1024 * @return success completion code if request data is valid
1025 * else return the correcponding error completion code.
1026 **/
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301027uint8_t getSessionInfoRequestData(const ipmi::Context::ptr ctx,
1028 const uint8_t sessionIndex,
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001029 ipmi::message::Payload& payload,
1030 uint32_t& reqSessionId,
1031 uint8_t& reqSessionHandle)
1032{
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301033 if ((sessionIndex > session::maxSessionCountPerChannel) &&
1034 (sessionIndex < session::searchSessionByHandle))
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001035 {
1036 return ipmi::ccInvalidFieldRequest;
1037 }
1038
1039 switch (sessionIndex)
1040 {
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301041 case session::searchCurrentSession:
1042
1043 ipmi::ChannelInfo chInfo;
1044 ipmi::getChannelInfo(ctx->channel, chInfo);
1045
1046 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) !=
1047 ipmi::EChannelMediumType::lan8032)
1048 {
1049 return ipmi::ccInvalidFieldRequest;
1050 }
1051
1052 if (!payload.fullyUnpacked())
1053 {
1054 return ipmi::ccReqDataLenInvalid;
1055 }
1056 // Check if current sessionId is 0, sessionId 0 is reserved.
1057 if (ctx->sessionId == session::sessionZero)
1058 {
1059 return session::ccInvalidSessionId;
1060 }
1061 reqSessionId = ctx->sessionId;
1062 break;
1063
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001064 case session::searchSessionByHandle:
1065
1066 if ((payload.unpack(reqSessionHandle)) ||
1067 (!payload.fullyUnpacked()))
1068 {
1069 return ipmi::ccReqDataLenInvalid;
1070 }
1071
1072 if ((reqSessionHandle == session::sessionZero) ||
1073 ((reqSessionHandle & session::multiIntfaceSessionHandleMask) >
1074 session::maxSessionCountPerChannel))
1075 {
1076 return session::ccInvalidSessionHandle;
1077 }
1078 break;
1079
1080 case session::searchSessionById:
1081
1082 if ((payload.unpack(reqSessionId)) || (!payload.fullyUnpacked()))
1083 {
1084 return ipmi::ccReqDataLenInvalid;
1085 }
1086
1087 if (reqSessionId == session::sessionZero)
1088 {
1089 return session::ccInvalidSessionId;
1090 }
1091 break;
1092
1093 default:
1094 if (!payload.fullyUnpacked())
1095 {
1096 return ipmi::ccReqDataLenInvalid;
1097 }
1098 break;
1099 }
1100 return ipmi::ccSuccess;
1101}
1102
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001103uint8_t getSessionState(ipmi::Context::ptr ctx, const std::string& service,
1104 const std::string& objPath, uint8_t& sessionState)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001105{
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001106 boost::system::error_code ec = ipmi::getDbusProperty(
1107 ctx, service, objPath, session::sessionIntf, "State", sessionState);
1108 if (ec)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001109 {
1110 log<level::ERR>("Failed to fetch state property ",
1111 entry("SERVICE=%s", service.c_str()),
1112 entry("OBJECTPATH=%s", objPath.c_str()),
1113 entry("INTERFACE=%s", session::sessionIntf),
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001114 entry("ERRMSG=%s", ec.message().c_str()));
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001115 return ipmi::ccUnspecifiedError;
1116 }
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001117 return ipmi::ccSuccess;
1118}
1119
1120static constexpr uint8_t macAddrLen = 6;
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001121/** Alias SessionDetails - contain the optional information about an
1122 * RMCP+ session.
1123 *
1124 * @param userID - uint6_t session user ID (0-63)
1125 * @param reserved - uint2_t reserved
1126 * @param privilege - uint4_t session privilege (0-5)
1127 * @param reserved - uint4_t reserved
1128 * @param channel - uint4_t session channel number
1129 * @param protocol - uint4_t session protocol
1130 * @param remoteIP - uint32_t remote IP address
1131 * @param macAddr - std::array<uint8_t, 6> mac address
1132 * @param port - uint16_t remote port
1133 */
1134using SessionDetails =
1135 std::tuple<uint2_t, uint6_t, uint4_t, uint4_t, uint4_t, uint4_t, uint32_t,
1136 std::array<uint8_t, macAddrLen>, uint16_t>;
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001137
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001138/** @brief get session details for a given session
1139 *
1140 * @param[in] ctx - ipmi::Context pointer for accessing D-Bus
1141 * @param[in] service - D-Bus service name to fetch details from
1142 * @param[in] objPath - D-Bus object path for session
1143 * @param[out] sessionHandle - return session handle for session
1144 * @param[out] sessionState - return session state for session
1145 * @param[out] details - return a SessionDetails tuple containing other
1146 * session info
1147 * @return - ipmi::Cc success or error code
1148 */
1149ipmi::Cc getSessionDetails(ipmi::Context::ptr ctx, const std::string& service,
1150 const std::string& objPath, uint8_t& sessionHandle,
1151 uint8_t& sessionState, SessionDetails& details)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001152{
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001153 ipmi::PropertyMap sessionProps;
1154 boost::system::error_code ec = ipmi::getAllDbusProperties(
1155 ctx, service, objPath, session::sessionIntf, sessionProps);
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001156
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001157 if (ec)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001158 {
1159 log<level::ERR>("Failed to fetch state property ",
1160 entry("SERVICE=%s", service.c_str()),
1161 entry("OBJECTPATH=%s", objPath.c_str()),
1162 entry("INTERFACE=%s", session::sessionIntf),
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001163 entry("ERRMSG=%s", ec.message().c_str()));
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001164 return ipmi::ccUnspecifiedError;
1165 }
1166
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001167 sessionState = ipmi::mappedVariant<uint8_t>(
1168 sessionProps, "State", static_cast<uint8_t>(session::State::inactive));
1169 if (sessionState == static_cast<uint8_t>(session::State::active))
1170 {
1171 sessionHandle =
1172 ipmi::mappedVariant<uint8_t>(sessionProps, "SessionHandle", 0);
1173 std::get<0>(details) =
1174 ipmi::mappedVariant<uint8_t>(sessionProps, "UserID", 0xff);
1175 // std::get<1>(details) = 0; // (default constructed to 0)
1176 std::get<2>(details) =
1177 ipmi::mappedVariant<uint8_t>(sessionProps, "CurrentPrivilege", 0);
1178 // std::get<3>(details) = 0; // (default constructed to 0)
1179 std::get<4>(details) =
1180 ipmi::mappedVariant<uint8_t>(sessionProps, "ChannelNum", 0xff);
1181 constexpr uint4_t rmcpPlusProtocol = 1;
1182 std::get<5>(details) = rmcpPlusProtocol;
1183 std::get<6>(details) =
1184 ipmi::mappedVariant<uint32_t>(sessionProps, "RemoteIPAddr", 0);
1185 // std::get<7>(details) = {{0}}; // default constructed to all 0
1186 std::get<8>(details) =
1187 ipmi::mappedVariant<uint16_t>(sessionProps, "RemotePort", 0);
1188 }
1189
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001190 return ipmi::ccSuccess;
1191}
1192
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001193ipmi::RspType<uint8_t, // session handle,
1194 uint8_t, // total session count
1195 uint8_t, // active session count
1196 std::optional<SessionDetails>>
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301197 ipmiAppGetSessionInfo(ipmi::Context::ptr ctx, uint8_t sessionIndex,
1198 ipmi::message::Payload& payload)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001199{
1200 uint32_t reqSessionId = 0;
1201 uint8_t reqSessionHandle = session::defaultSessionHandle;
1202 // initializing state to 0xff as 0 represents state as inactive.
1203 uint8_t state = 0xFF;
1204
1205 uint8_t completionCode = getSessionInfoRequestData(
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301206 ctx, sessionIndex, payload, reqSessionId, reqSessionHandle);
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001207
1208 if (completionCode)
1209 {
1210 return ipmi::response(completionCode);
1211 }
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001212 ipmi::ObjectTree objectTree;
1213 boost::system::error_code ec = ipmi::getAllDbusObjects(
1214 ctx, session::sessionManagerRootPath, session::sessionIntf, objectTree);
1215 if (ec)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001216 {
1217 log<level::ERR>("Failed to fetch object from dbus",
1218 entry("INTERFACE=%s", session::sessionIntf),
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001219 entry("ERRMSG=%s", ec.message().c_str()));
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001220 return ipmi::responseUnspecifiedError();
1221 }
1222
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001223 uint8_t totalSessionCount = getTotalSessionCount();
1224 uint8_t activeSessionCount = 0;
1225 uint8_t sessionHandle = session::defaultSessionHandle;
1226 std::optional<SessionDetails> maybeDetails;
1227 uint8_t index = 0;
1228 for (auto& objectTreeItr : objectTree)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001229 {
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001230 uint32_t sessionId = 0;
1231 std::string objectPath = objectTreeItr.first;
1232
1233 if (!parseCloseSessionInputPayload(objectPath, sessionId,
1234 sessionHandle))
1235 {
1236 continue;
1237 }
1238 index++;
1239 auto& serviceMap = objectTreeItr.second;
1240 auto itr = serviceMap.begin();
1241
1242 if (serviceMap.size() != 1)
1243 {
1244 return ipmi::responseUnspecifiedError();
1245 }
1246
1247 std::string service = itr->first;
1248 uint8_t sessionState = 0;
1249 completionCode =
1250 getSessionState(ctx, service, objectPath, sessionState);
1251 if (completionCode)
1252 {
1253 return ipmi::response(completionCode);
1254 }
1255
1256 if (sessionState == static_cast<uint8_t>(session::State::active))
1257 {
1258 activeSessionCount++;
1259 }
1260
1261 if (index != sessionIndex && reqSessionId != sessionId &&
1262 reqSessionHandle != sessionHandle)
1263 {
1264 continue;
1265 }
1266
1267 SessionDetails details{};
1268 completionCode = getSessionDetails(ctx, service, objectPath,
1269 sessionHandle, state, details);
1270
1271 if (completionCode)
1272 {
1273 return ipmi::response(completionCode);
1274 }
1275 maybeDetails = std::move(details);
Brian Ma61880882022-07-15 09:34:07 +08001276 break;
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001277 }
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001278
1279 if (state == static_cast<uint8_t>(session::State::active) ||
1280 state == static_cast<uint8_t>(session::State::tearDownInProgress))
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001281 {
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001282 return ipmi::responseSuccess(sessionHandle, totalSessionCount,
1283 activeSessionCount, maybeDetails);
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001284 }
1285
1286 return ipmi::responseInvalidFieldRequest();
1287}
1288
Xo Wangf542e8b2017-08-09 15:34:16 -07001289static std::unique_ptr<SysInfoParamStore> sysInfoParamStore;
1290
Xo Wang87651332017-08-11 10:17:59 -07001291static std::string sysInfoReadSystemName()
1292{
1293 // Use the BMC hostname as the "System Name."
1294 char hostname[HOST_NAME_MAX + 1] = {};
1295 if (gethostname(hostname, HOST_NAME_MAX) != 0)
1296 {
1297 perror("System info parameter: system name");
1298 }
1299 return hostname;
1300}
1301
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001302static constexpr uint8_t paramRevision = 0x11;
1303static constexpr size_t configParameterLength = 16;
Xo Wangf542e8b2017-08-09 15:34:16 -07001304
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001305static constexpr size_t smallChunkSize = 14;
1306static constexpr size_t fullChunkSize = 16;
Jia, chunhui449f2162019-09-11 16:51:51 +08001307static constexpr uint8_t progressMask = 0x3;
Xo Wangf542e8b2017-08-09 15:34:16 -07001308
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001309static constexpr uint8_t setComplete = 0x0;
1310static constexpr uint8_t setInProgress = 0x1;
1311static constexpr uint8_t commitWrite = 0x2;
1312static uint8_t transferStatus = setComplete;
1313
Jia, chunhui449f2162019-09-11 16:51:51 +08001314static constexpr uint8_t configDataOverhead = 2;
1315
1316// For EFI based system, 256 bytes is recommended.
1317static constexpr size_t maxBytesPerParameter = 256;
1318
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001319namespace ipmi
1320{
1321constexpr Cc ccParmNotSupported = 0x80;
Jia, chunhui449f2162019-09-11 16:51:51 +08001322constexpr Cc ccSetInProgressActive = 0x81;
1323constexpr Cc ccSystemInfoParameterSetReadOnly = 0x82;
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001324
1325static inline auto responseParmNotSupported()
1326{
1327 return response(ccParmNotSupported);
Xo Wangf542e8b2017-08-09 15:34:16 -07001328}
Jia, chunhui449f2162019-09-11 16:51:51 +08001329static inline auto responseSetInProgressActive()
1330{
1331 return response(ccSetInProgressActive);
1332}
1333static inline auto responseSystemInfoParameterSetReadOnly()
1334{
1335 return response(ccSystemInfoParameterSetReadOnly);
1336}
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001337} // namespace ipmi
Xo Wangf542e8b2017-08-09 15:34:16 -07001338
Jia, chunhui449f2162019-09-11 16:51:51 +08001339ipmi::RspType<uint8_t, // Parameter revision
1340 std::optional<uint8_t>, // data1 / setSelector / ProgressStatus
1341 std::optional<std::vector<uint8_t>>> // data2-17
jayaprakash Mutyalac2566a92020-04-23 21:18:35 +00001342 ipmiAppGetSystemInfo(uint7_t reserved, bool getRevision,
1343 uint8_t paramSelector, uint8_t setSelector,
1344 uint8_t BlockSelector)
Xo Wangf542e8b2017-08-09 15:34:16 -07001345{
Snehalatha Va5ae7722020-05-02 18:18:57 +00001346 if (reserved || (paramSelector >= invalidParamSelectorStart &&
1347 paramSelector <= invalidParamSelectorEnd))
jayaprakash Mutyalac2566a92020-04-23 21:18:35 +00001348 {
1349 return ipmi::responseInvalidFieldRequest();
1350 }
Snehalatha Va5ae7722020-05-02 18:18:57 +00001351 if ((paramSelector >= oemCmdStart) && (paramSelector <= oemCmdEnd))
1352 {
1353 return ipmi::responseParmNotSupported();
1354 }
jayaprakash Mutyalac2566a92020-04-23 21:18:35 +00001355 if (getRevision)
Xo Wangf542e8b2017-08-09 15:34:16 -07001356 {
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001357 return ipmi::responseSuccess(paramRevision, std::nullopt, std::nullopt);
Xo Wangf542e8b2017-08-09 15:34:16 -07001358 }
1359
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001360 if (paramSelector == 0)
Xo Wangf542e8b2017-08-09 15:34:16 -07001361 {
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001362 return ipmi::responseSuccess(paramRevision, transferStatus,
1363 std::nullopt);
Xo Wangf542e8b2017-08-09 15:34:16 -07001364 }
1365
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001366 if (BlockSelector != 0) // 00h if parameter does not require a block number
Xo Wangf542e8b2017-08-09 15:34:16 -07001367 {
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001368 return ipmi::responseParmNotSupported();
Xo Wangf542e8b2017-08-09 15:34:16 -07001369 }
1370
1371 if (sysInfoParamStore == nullptr)
1372 {
1373 sysInfoParamStore = std::make_unique<SysInfoParamStore>();
Xo Wang87651332017-08-11 10:17:59 -07001374 sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME,
1375 sysInfoReadSystemName);
Xo Wangf542e8b2017-08-09 15:34:16 -07001376 }
1377
1378 // Parameters other than Set In Progress are assumed to be strings.
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001379 std::tuple<bool, std::string> ret =
1380 sysInfoParamStore->lookup(paramSelector);
1381 bool found = std::get<0>(ret);
Xo Wangf542e8b2017-08-09 15:34:16 -07001382 if (!found)
1383 {
Snehalatha Va5ae7722020-05-02 18:18:57 +00001384 return ipmi::responseSensorInvalid();
Xo Wangf542e8b2017-08-09 15:34:16 -07001385 }
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001386 std::string& paramString = std::get<1>(ret);
Jia, chunhui449f2162019-09-11 16:51:51 +08001387 std::vector<uint8_t> configData;
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001388 size_t count = 0;
1389 if (setSelector == 0)
Jia, chunhui449f2162019-09-11 16:51:51 +08001390 { // First chunk has only 14 bytes.
1391 configData.emplace_back(0); // encoding
1392 configData.emplace_back(paramString.length()); // string length
1393 count = std::min(paramString.length(), smallChunkSize);
1394 configData.resize(count + configDataOverhead);
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001395 std::copy_n(paramString.begin(), count,
Snehalatha Va5ae7722020-05-02 18:18:57 +00001396 configData.begin() + configDataOverhead); // 14 bytes chunk
1397
1398 // Append zero's to remaining bytes
1399 if (configData.size() < configParameterLength)
1400 {
1401 std::fill_n(std::back_inserter(configData),
1402 configParameterLength - configData.size(), 0x00);
1403 }
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001404 }
1405 else
Xo Wangf542e8b2017-08-09 15:34:16 -07001406 {
Jia, chunhui449f2162019-09-11 16:51:51 +08001407 size_t offset = (setSelector * fullChunkSize) - configDataOverhead;
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001408 if (offset >= paramString.length())
1409 {
1410 return ipmi::responseParmOutOfRange();
1411 }
Jia, chunhui449f2162019-09-11 16:51:51 +08001412 count = std::min(paramString.length() - offset, fullChunkSize);
1413 configData.resize(count);
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001414 std::copy_n(paramString.begin() + offset, count,
1415 configData.begin()); // 16 bytes chunk
Xo Wangf542e8b2017-08-09 15:34:16 -07001416 }
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001417 return ipmi::responseSuccess(paramRevision, setSelector, configData);
Xo Wangf542e8b2017-08-09 15:34:16 -07001418}
1419
Jia, chunhui449f2162019-09-11 16:51:51 +08001420ipmi::RspType<> ipmiAppSetSystemInfo(uint8_t paramSelector, uint8_t data1,
1421 std::vector<uint8_t> configData)
1422{
jayaprakash Mutyala3c5e4132020-04-27 23:00:05 +00001423 if (paramSelector >= invalidParamSelectorStart &&
1424 paramSelector <= invalidParamSelectorEnd)
1425 {
1426 return ipmi::responseInvalidFieldRequest();
1427 }
1428 if ((paramSelector >= oemCmdStart) && (paramSelector <= oemCmdEnd))
1429 {
1430 return ipmi::responseParmNotSupported();
1431 }
1432
Jia, chunhui449f2162019-09-11 16:51:51 +08001433 if (paramSelector == 0)
1434 {
1435 // attempt to set the 'set in progress' value (in parameter #0)
1436 // when not in the set complete state.
1437 if ((transferStatus != setComplete) && (data1 == setInProgress))
1438 {
1439 return ipmi::responseSetInProgressActive();
1440 }
1441 // only following 2 states are supported
1442 if (data1 > setInProgress)
1443 {
1444 phosphor::logging::log<phosphor::logging::level::ERR>(
1445 "illegal SetInProgress status");
1446 return ipmi::responseInvalidFieldRequest();
1447 }
1448
1449 transferStatus = data1 & progressMask;
1450 return ipmi::responseSuccess();
1451 }
1452
1453 if (configData.size() > configParameterLength)
1454 {
1455 return ipmi::responseInvalidFieldRequest();
1456 }
1457
jayaprakash Mutyala3c5e4132020-04-27 23:00:05 +00001458 // Append zero's to remaining bytes
1459 if (configData.size() < configParameterLength)
1460 {
1461 fill_n(back_inserter(configData),
1462 (configParameterLength - configData.size()), 0x00);
1463 }
1464
Jia, chunhui449f2162019-09-11 16:51:51 +08001465 if (!sysInfoParamStore)
1466 {
1467 sysInfoParamStore = std::make_unique<SysInfoParamStore>();
1468 sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME,
1469 sysInfoReadSystemName);
1470 }
1471
1472 // lookup
1473 std::tuple<bool, std::string> ret =
1474 sysInfoParamStore->lookup(paramSelector);
1475 bool found = std::get<0>(ret);
1476 std::string& paramString = std::get<1>(ret);
1477 if (!found)
1478 {
1479 // parameter does not exist. Init new
1480 paramString = "";
1481 }
1482
1483 uint8_t setSelector = data1;
1484 size_t count = 0;
1485 if (setSelector == 0) // First chunk has only 14 bytes.
1486 {
1487 size_t stringLen = configData.at(1); // string length
1488 // maxBytesPerParamter is 256. It will always be greater than stringLen
1489 // (unit8_t) if maxBytes changes in future, then following line is
1490 // needed.
1491 // stringLen = std::min(stringLen, maxBytesPerParameter);
1492 count = std::min(stringLen, smallChunkSize);
1493 count = std::min(count, configData.size());
1494 paramString.resize(stringLen); // reserve space
1495 std::copy_n(configData.begin() + configDataOverhead, count,
1496 paramString.begin());
1497 }
1498 else
1499 {
1500 size_t offset = (setSelector * fullChunkSize) - configDataOverhead;
1501 if (offset >= paramString.length())
1502 {
1503 return ipmi::responseParmOutOfRange();
1504 }
1505 count = std::min(paramString.length() - offset, configData.size());
1506 std::copy_n(configData.begin(), count, paramString.begin() + offset);
1507 }
1508 sysInfoParamStore->update(paramSelector, paramString);
1509 return ipmi::responseSuccess();
1510}
1511
Yong Libd0503a2019-08-22 17:17:17 +08001512#ifdef ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301513inline std::vector<uint8_t> convertStringToData(const std::string& command)
1514{
1515 std::istringstream iss(command);
1516 std::string token;
1517 std::vector<uint8_t> dataValue;
1518 while (std::getline(iss, token, ' '))
1519 {
1520 dataValue.emplace_back(
1521 static_cast<uint8_t>(std::stoul(token, nullptr, base_16)));
1522 }
1523 return dataValue;
1524}
1525
1526static bool populateI2CMasterWRWhitelist()
1527{
1528 nlohmann::json data = nullptr;
1529 std::ifstream jsonFile(i2cMasterWRWhitelistFile);
1530
1531 if (!jsonFile.good())
1532 {
1533 log<level::WARNING>("i2c white list file not found!",
1534 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile));
1535 return false;
1536 }
1537
1538 try
1539 {
1540 data = nlohmann::json::parse(jsonFile, nullptr, false);
1541 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001542 catch (const nlohmann::json::parse_error& e)
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301543 {
1544 log<level::ERR>("Corrupted i2c white list config file",
1545 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile),
1546 entry("MSG: %s", e.what()));
1547 return false;
1548 }
1549
1550 try
1551 {
1552 // Example JSON Structure format
1553 // "filters": [
1554 // {
1555 // "Description": "Allow full read - ignore first byte write value
1556 // for 0x40 to 0x4F",
1557 // "busId": "0x01",
1558 // "slaveAddr": "0x40",
1559 // "slaveAddrMask": "0x0F",
1560 // "command": "0x00",
1561 // "commandMask": "0xFF"
1562 // },
1563 // {
1564 // "Description": "Allow full read - first byte match 0x05 and
1565 // ignore second byte",
1566 // "busId": "0x01",
1567 // "slaveAddr": "0x57",
1568 // "slaveAddrMask": "0x00",
1569 // "command": "0x05 0x00",
1570 // "commandMask": "0x00 0xFF"
1571 // },]
1572
1573 nlohmann::json filters = data[filtersStr].get<nlohmann::json>();
1574 std::vector<i2cMasterWRWhitelist>& whitelist = getWRWhitelist();
1575 for (const auto& it : filters.items())
1576 {
1577 nlohmann::json filter = it.value();
1578 if (filter.is_null())
1579 {
1580 log<level::ERR>(
1581 "Corrupted I2C master write read whitelist config file",
1582 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile));
1583 return false;
1584 }
1585 const std::vector<uint8_t>& writeData =
1586 convertStringToData(filter[cmdStr].get<std::string>());
1587 const std::vector<uint8_t>& writeDataMask =
1588 convertStringToData(filter[cmdMaskStr].get<std::string>());
1589 if (writeDataMask.size() != writeData.size())
1590 {
1591 log<level::ERR>("I2C master write read whitelist filter "
1592 "mismatch for command & mask size");
1593 return false;
1594 }
1595 whitelist.push_back(
1596 {static_cast<uint8_t>(std::stoul(
1597 filter[busIdStr].get<std::string>(), nullptr, base_16)),
1598 static_cast<uint8_t>(
1599 std::stoul(filter[slaveAddrStr].get<std::string>(),
1600 nullptr, base_16)),
1601 static_cast<uint8_t>(
1602 std::stoul(filter[slaveAddrMaskStr].get<std::string>(),
1603 nullptr, base_16)),
1604 writeData, writeDataMask});
1605 }
1606 if (whitelist.size() != filters.size())
1607 {
1608 log<level::ERR>(
1609 "I2C master write read whitelist filter size mismatch");
1610 return false;
1611 }
1612 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001613 catch (const std::exception& e)
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301614 {
1615 log<level::ERR>("I2C master write read whitelist unexpected exception",
1616 entry("ERROR=%s", e.what()));
1617 return false;
1618 }
1619 return true;
1620}
1621
1622static inline bool isWriteDataWhitelisted(const std::vector<uint8_t>& data,
1623 const std::vector<uint8_t>& dataMask,
1624 const std::vector<uint8_t>& writeData)
1625{
1626 std::vector<uint8_t> processedDataBuf(data.size());
1627 std::vector<uint8_t> processedReqBuf(dataMask.size());
1628 std::transform(writeData.begin(), writeData.end(), dataMask.begin(),
1629 processedReqBuf.begin(), std::bit_or<uint8_t>());
1630 std::transform(data.begin(), data.end(), dataMask.begin(),
1631 processedDataBuf.begin(), std::bit_or<uint8_t>());
1632
1633 return (processedDataBuf == processedReqBuf);
1634}
1635
1636static bool isCmdWhitelisted(uint8_t busId, uint8_t slaveAddr,
1637 std::vector<uint8_t>& writeData)
1638{
1639 std::vector<i2cMasterWRWhitelist>& whiteList = getWRWhitelist();
1640 for (const auto& wlEntry : whiteList)
1641 {
1642 if ((busId == wlEntry.busId) &&
1643 ((slaveAddr | wlEntry.slaveAddrMask) ==
1644 (wlEntry.slaveAddr | wlEntry.slaveAddrMask)))
1645 {
1646 const std::vector<uint8_t>& dataMask = wlEntry.dataMask;
1647 // Skip as no-match, if requested write data is more than the
1648 // write data mask size
1649 if (writeData.size() > dataMask.size())
1650 {
1651 continue;
1652 }
1653 if (isWriteDataWhitelisted(wlEntry.data, dataMask, writeData))
1654 {
1655 return true;
1656 }
1657 }
1658 }
1659 return false;
1660}
Yong Libd0503a2019-08-22 17:17:17 +08001661#else
1662static bool populateI2CMasterWRWhitelist()
1663{
1664 log<level::INFO>(
1665 "I2C_WHITELIST_CHECK is disabled, do not populate whitelist");
1666 return true;
1667}
1668#endif // ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301669
1670/** @brief implements master write read IPMI command which can be used for
1671 * low-level I2C/SMBus write, read or write-read access
1672 * @param isPrivateBus -to indicate private bus usage
1673 * @param busId - bus id
1674 * @param channelNum - channel number
1675 * @param reserved - skip 1 bit
1676 * @param slaveAddr - slave address
1677 * @param read count - number of bytes to be read
1678 * @param writeData - data to be written
1679 *
1680 * @returns IPMI completion code plus response data
1681 * - readData - i2c response data
1682 */
1683ipmi::RspType<std::vector<uint8_t>>
Willy Tu11d68892022-01-20 10:37:34 -08001684 ipmiMasterWriteRead([[maybe_unused]] bool isPrivateBus, uint3_t busId,
1685 [[maybe_unused]] uint4_t channelNum, bool reserved,
1686 uint7_t slaveAddr, uint8_t readCount,
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301687 std::vector<uint8_t> writeData)
1688{
Jayaprakash Mutyalac2af98b2021-09-14 09:19:11 +00001689 if (reserved)
1690 {
1691 return ipmi::responseInvalidFieldRequest();
1692 }
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301693 if (readCount > maxIPMIWriteReadSize)
1694 {
1695 log<level::ERR>("Master write read command: Read count exceeds limit");
1696 return ipmi::responseParmOutOfRange();
1697 }
1698 const size_t writeCount = writeData.size();
1699 if (!readCount && !writeCount)
1700 {
1701 log<level::ERR>("Master write read command: Read & write count are 0");
1702 return ipmi::responseInvalidFieldRequest();
1703 }
Yong Libd0503a2019-08-22 17:17:17 +08001704#ifdef ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301705 if (!isCmdWhitelisted(static_cast<uint8_t>(busId),
1706 static_cast<uint8_t>(slaveAddr), writeData))
1707 {
1708 log<level::ERR>("Master write read request blocked!",
1709 entry("BUS=%d", static_cast<uint8_t>(busId)),
1710 entry("ADDR=0x%x", static_cast<uint8_t>(slaveAddr)));
1711 return ipmi::responseInvalidFieldRequest();
1712 }
Yong Libd0503a2019-08-22 17:17:17 +08001713#endif // ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301714 std::vector<uint8_t> readBuf(readCount);
1715 std::string i2cBus =
1716 "/dev/i2c-" + std::to_string(static_cast<uint8_t>(busId));
1717
Yong Li7dc4ac02019-08-23 17:44:32 +08001718 ipmi::Cc ret = ipmi::i2cWriteRead(i2cBus, static_cast<uint8_t>(slaveAddr),
1719 writeData, readBuf);
1720 if (ret != ipmi::ccSuccess)
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301721 {
Yong Li7dc4ac02019-08-23 17:44:32 +08001722 return ipmi::response(ret);
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301723 }
1724 return ipmi::responseSuccess(readBuf);
1725}
1726
Chris Austen6caf28b2015-10-13 12:40:40 -05001727void register_netfn_app_functions()
vishwabmcba0bd5f2015-09-30 16:50:23 +05301728{
Vernon Mauery86a50822019-03-25 13:11:36 -07001729 // <Get Device ID>
1730 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1731 ipmi::app::cmdGetDeviceId, ipmi::Privilege::User,
1732 ipmiAppGetDeviceId);
1733
Tom05732372016-09-06 17:21:23 +05301734 // <Get BT Interface Capabilities>
Vernon Mauerycc99ba42019-03-25 13:40:11 -07001735 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1736 ipmi::app::cmdGetBtIfaceCapabilities,
1737 ipmi::Privilege::User, ipmiAppGetBtCapabilities);
Chris Austen6caf28b2015-10-13 12:40:40 -05001738
Tom05732372016-09-06 17:21:23 +05301739 // <Reset Watchdog Timer>
Vernon Mauery11df4f62019-03-25 14:17:54 -07001740 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1741 ipmi::app::cmdResetWatchdogTimer,
1742 ipmi::Privilege::Operator, ipmiAppResetWatchdogTimer);
Chris Austen6caf28b2015-10-13 12:40:40 -05001743
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001744 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
AppaRao Puli5a98ea62019-11-10 21:15:02 +05301745 ipmi::app::cmdGetSessionInfo, ipmi::Privilege::User,
1746 ipmiAppGetSessionInfo);
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001747
Tom05732372016-09-06 17:21:23 +05301748 // <Set Watchdog Timer>
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +00001749 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1750 ipmi::app::cmdSetWatchdogTimer,
1751 ipmi::Privilege::Operator, ipmiSetWatchdogTimer);
Chris Austen6caf28b2015-10-13 12:40:40 -05001752
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +00001753 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1754 ipmi::app::cmdCloseSession, ipmi::Privilege::Callback,
1755 ipmiAppCloseSession);
1756
William A. Kennington III73f44512018-02-09 15:28:46 -08001757 // <Get Watchdog Timer>
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +00001758 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
AppaRao Puli5a98ea62019-11-10 21:15:02 +05301759 ipmi::app::cmdGetWatchdogTimer, ipmi::Privilege::User,
1760 ipmiGetWatchdogTimer);
William A. Kennington III73f44512018-02-09 15:28:46 -08001761
Tom05732372016-09-06 17:21:23 +05301762 // <Get Self Test Results>
Vernon Maueryb84a5282019-03-25 13:39:03 -07001763 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1764 ipmi::app::cmdGetSelfTestResults,
1765 ipmi::Privilege::User, ipmiAppGetSelfTestResults);
Nan Li41fa24a2016-11-10 20:12:37 +08001766
Tom05732372016-09-06 17:21:23 +05301767 // <Get Device GUID>
Vernon Mauery15541322019-03-25 13:33:03 -07001768 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1769 ipmi::app::cmdGetDeviceGuid, ipmi::Privilege::User,
1770 ipmiAppGetDeviceGuid);
Adriana Kobylakd100ee52015-10-20 17:02:37 -05001771
Tom05732372016-09-06 17:21:23 +05301772 // <Set ACPI Power State>
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +00001773 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1774 ipmi::app::cmdSetAcpiPowerState,
1775 ipmi::Privilege::Admin, ipmiSetAcpiPowerState);
Yong Li18d77262018-10-09 01:59:45 +08001776 // <Get ACPI Power State>
Deepak Kumar Sahu4e6d2572019-05-07 19:53:37 +00001777 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1778 ipmi::app::cmdGetAcpiPowerState,
AppaRao Puli5a98ea62019-11-10 21:15:02 +05301779 ipmi::Privilege::User, ipmiGetAcpiPowerState);
Yong Li18d77262018-10-09 01:59:45 +08001780
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301781 // Note: For security reason, this command will be registered only when
1782 // there are proper I2C Master write read whitelist
1783 if (populateI2CMasterWRWhitelist())
1784 {
1785 // Note: For security reasons, registering master write read as admin
1786 // privilege command, even though IPMI 2.0 specification allows it as
1787 // operator privilege.
1788 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1789 ipmi::app::cmdMasterWriteRead,
1790 ipmi::Privilege::Admin, ipmiMasterWriteRead);
1791 }
1792
Marri Devender Rao5e007a52018-01-08 06:18:36 -06001793 // <Get System GUID Command>
Vernon Maueryb90a5322019-03-25 13:36:55 -07001794 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1795 ipmi::app::cmdGetSystemGuid, ipmi::Privilege::User,
1796 ipmiAppGetSystemGuid);
Tom Joseph7cbe2282018-03-21 21:17:33 +05301797
1798 // <Get Channel Cipher Suites Command>
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +00001799 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1800 ipmi::app::cmdGetChannelCipherSuites,
Vernon Mauery79b4eea2019-11-07 09:51:39 -08001801 ipmi::Privilege::None, getChannelCipherSuites);
Vernon Maueryd2a57de2019-03-25 12:45:28 -07001802
Xo Wangf542e8b2017-08-09 15:34:16 -07001803 // <Get System Info Command>
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001804 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1805 ipmi::app::cmdGetSystemInfoParameters,
1806 ipmi::Privilege::User, ipmiAppGetSystemInfo);
Jia, chunhui449f2162019-09-11 16:51:51 +08001807 // <Set System Info Command>
1808 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1809 ipmi::app::cmdSetSystemInfoParameters,
1810 ipmi::Privilege::Admin, ipmiAppSetSystemInfo);
vishwabmcba0bd5f2015-09-30 16:50:23 +05301811 return;
1812}