blob: 6591afabfed6d01e58d68c1209c7d0467acd2d8b [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{
Vernon Mauery86a50822019-03-25 13:11:36 -0700622 static struct
623 {
624 uint8_t id;
625 uint8_t revision;
626 uint8_t fw[2];
627 uint8_t ipmiVer;
628 uint8_t addnDevSupport;
629 uint24_t manufId;
630 uint16_t prodId;
631 uint32_t aux;
632 } devId;
David Cobbleya1adb072017-11-21 15:58:13 -0800633 static bool dev_id_initialized = false;
Patrick Venture94930a12019-04-30 10:01:58 -0700634 static bool defaultActivationSetting = true;
David Cobbleya1adb072017-11-21 15:58:13 -0800635 const char* filename = "/usr/share/ipmi-providers/dev_id.json";
Alexander Amelkinba19c182018-09-04 15:49:36 +0300636 constexpr auto ipmiDevIdStateShift = 7;
637 constexpr auto ipmiDevIdFw1Mask = ~(1 << ipmiDevIdStateShift);
Willy Tub78184e2022-10-27 22:57:38 +0000638
639#ifdef GET_DBUS_ACTIVE_SOFTWARE
640 static bool haveBMCVersion = false;
JeffLin27a62ec2021-11-24 15:40:33 +0800641 if (!haveBMCVersion || !dev_id_initialized)
David Cobbleya1adb072017-11-21 15:58:13 -0800642 {
Willy Tub78184e2022-10-27 22:57:38 +0000643 int r = -1;
644 Revision rev = {0, 0, 0, 0};
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600645 try
646 {
Vernon Maueryea1c4012019-05-24 13:26:16 -0700647 auto version = getActiveSoftwareVersionInfo(ctx);
Vernon Mauery86a50822019-03-25 13:11:36 -0700648 r = convertVersion(version, rev);
David Cobbleya1adb072017-11-21 15:58:13 -0800649 }
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600650 catch (const std::exception& e)
651 {
652 log<level::ERR>(e.what());
653 }
Nan Liee0cb902016-07-11 15:38:03 +0800654
Patrick Venture0b02be92018-08-31 11:55:55 -0700655 if (r >= 0)
656 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600657 // bit7 identifies if the device is available
658 // 0=normal operation
659 // 1=device firmware, SDR update,
660 // or self-initialization in progress.
Alexander Amelkinba19c182018-09-04 15:49:36 +0300661 // The availability may change in run time, so mask here
662 // and initialize later.
Vernon Mauery86a50822019-03-25 13:11:36 -0700663 devId.fw[0] = rev.major & ipmiDevIdFw1Mask;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600664
665 rev.minor = (rev.minor > 99 ? 99 : rev.minor);
Vernon Mauery86a50822019-03-25 13:11:36 -0700666 devId.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16;
667 std::memcpy(&devId.aux, rev.d, 4);
Brandon Kimc1f5aca2022-03-17 17:54:06 -0700668 haveBMCVersion = true;
David Cobbleya1adb072017-11-21 15:58:13 -0800669 }
JeffLin27a62ec2021-11-24 15:40:33 +0800670 }
Willy Tub78184e2022-10-27 22:57:38 +0000671#endif
JeffLin27a62ec2021-11-24 15:40:33 +0800672 if (!dev_id_initialized)
673 {
David Cobbleya1adb072017-11-21 15:58:13 -0800674 // IPMI Spec version 2.0
Vernon Mauery86a50822019-03-25 13:11:36 -0700675 devId.ipmiVer = 2;
Adriana Kobylak0e912642016-06-22 16:54:39 -0500676
Vernon Mauery86a50822019-03-25 13:11:36 -0700677 std::ifstream devIdFile(filename);
678 if (devIdFile.is_open())
David Cobbleya1adb072017-11-21 15:58:13 -0800679 {
Vernon Mauery86a50822019-03-25 13:11:36 -0700680 auto data = nlohmann::json::parse(devIdFile, nullptr, false);
David Cobbleya1adb072017-11-21 15:58:13 -0800681 if (!data.is_discarded())
682 {
Vernon Mauery86a50822019-03-25 13:11:36 -0700683 devId.id = data.value("id", 0);
684 devId.revision = data.value("revision", 0);
685 devId.addnDevSupport = data.value("addn_dev_support", 0);
686 devId.manufId = data.value("manuf_id", 0);
687 devId.prodId = data.value("prod_id", 0);
688 devId.aux = data.value("aux", 0);
David Cobbleya1adb072017-11-21 15:58:13 -0800689
Willy Tubfd3a172022-05-31 13:57:54 -0700690 if (data.contains("firmware_revision"))
691 {
692 const auto& firmwareRevision = data.at("firmware_revision");
693 if (firmwareRevision.contains("major"))
694 {
695 firmwareRevision.at("major").get_to(devId.fw[0]);
696 }
697 if (firmwareRevision.contains("minor"))
698 {
699 firmwareRevision.at("minor").get_to(devId.fw[1]);
700 }
701 }
702
Patrick Venture94930a12019-04-30 10:01:58 -0700703 // Set the availablitity of the BMC.
704 defaultActivationSetting = data.value("availability", true);
705
Patrick Venture0b02be92018-08-31 11:55:55 -0700706 // Don't read the file every time if successful
David Cobbleya1adb072017-11-21 15:58:13 -0800707 dev_id_initialized = true;
708 }
709 else
710 {
711 log<level::ERR>("Device ID JSON parser failure");
Vernon Maueryf2587fc2019-04-09 14:28:15 -0700712 return ipmi::responseUnspecifiedError();
David Cobbleya1adb072017-11-21 15:58:13 -0800713 }
714 }
715 else
716 {
717 log<level::ERR>("Device ID file not found");
Vernon Maueryf2587fc2019-04-09 14:28:15 -0700718 return ipmi::responseUnspecifiedError();
Chris Austen7303bdc2016-04-17 11:50:54 -0500719 }
720 }
Chris Austen6caf28b2015-10-13 12:40:40 -0500721
Alexander Amelkinba19c182018-09-04 15:49:36 +0300722 // Set availability to the actual current BMC state
Vernon Mauery86a50822019-03-25 13:11:36 -0700723 devId.fw[0] &= ipmiDevIdFw1Mask;
Patrick Venture94930a12019-04-30 10:01:58 -0700724 if (!getCurrentBmcStateWithFallback(defaultActivationSetting))
Alexander Amelkinba19c182018-09-04 15:49:36 +0300725 {
Vernon Mauery86a50822019-03-25 13:11:36 -0700726 devId.fw[0] |= (1 << ipmiDevIdStateShift);
Alexander Amelkinba19c182018-09-04 15:49:36 +0300727 }
728
Vernon Mauery86a50822019-03-25 13:11:36 -0700729 return ipmi::responseSuccess(
730 devId.id, devId.revision, devId.fw[0], devId.fw[1], devId.ipmiVer,
731 devId.addnDevSupport, devId.manufId, devId.prodId, devId.aux);
Chris Austen6caf28b2015-10-13 12:40:40 -0500732}
733
Vernon Maueryb84a5282019-03-25 13:39:03 -0700734auto ipmiAppGetSelfTestResults() -> ipmi::RspType<uint8_t, uint8_t>
Nan Li41fa24a2016-11-10 20:12:37 +0800735{
Nan Li41fa24a2016-11-10 20:12:37 +0800736 // Byte 2:
737 // 55h - No error.
Gunnar Mills8991dd62017-10-25 17:11:29 -0500738 // 56h - Self Test function not implemented in this controller.
Nan Li41fa24a2016-11-10 20:12:37 +0800739 // 57h - Corrupted or inaccesssible data or devices.
740 // 58h - Fatal hardware error.
741 // FFh - reserved.
742 // all other: Device-specific 'internal failure'.
743 // Byte 3:
744 // For byte 2 = 55h, 56h, FFh: 00h
745 // For byte 2 = 58h, all other: Device-specific
746 // For byte 2 = 57h: self-test error bitfield.
747 // Note: returning 57h does not imply that all test were run.
748 // [7] 1b = Cannot access SEL device.
749 // [6] 1b = Cannot access SDR Repository.
750 // [5] 1b = Cannot access BMC FRU device.
751 // [4] 1b = IPMB signal lines do not respond.
752 // [3] 1b = SDR Repository empty.
753 // [2] 1b = Internal Use Area of BMC FRU corrupted.
754 // [1] 1b = controller update 'boot block' firmware corrupted.
755 // [0] 1b = controller operational firmware corrupted.
Vernon Maueryb84a5282019-03-25 13:39:03 -0700756 constexpr uint8_t notImplemented = 0x56;
757 constexpr uint8_t zero = 0;
758 return ipmi::responseSuccess(notImplemented, zero);
Nan Li41fa24a2016-11-10 20:12:37 +0800759}
760
Vernon Mauery15541322019-03-25 13:33:03 -0700761static constexpr size_t uuidBinaryLength = 16;
762static std::array<uint8_t, uuidBinaryLength> rfc4122ToIpmi(std::string rfc4122)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500763{
Vernon Mauery15541322019-03-25 13:33:03 -0700764 using Argument = xyz::openbmc_project::Common::InvalidArgument;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500765 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Patrick Ventured2117022018-02-06 08:54:37 -0800766 // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte
767 // order
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500768 // Ex: 0x2332fc2c40e66298e511f2782395a361
Vernon Mauery15541322019-03-25 13:33:03 -0700769 constexpr size_t uuidHexLength = (2 * uuidBinaryLength);
770 constexpr size_t uuidRfc4122Length = (uuidHexLength + 4);
771 std::array<uint8_t, uuidBinaryLength> uuid;
772 if (rfc4122.size() == uuidRfc4122Length)
Patrick Venture0b02be92018-08-31 11:55:55 -0700773 {
Vernon Mauery15541322019-03-25 13:33:03 -0700774 rfc4122.erase(std::remove(rfc4122.begin(), rfc4122.end(), '-'),
775 rfc4122.end());
Sergey Solomineb9b8142016-08-23 09:07:28 -0500776 }
Vernon Mauery15541322019-03-25 13:33:03 -0700777 if (rfc4122.size() != uuidHexLength)
vishwa1eaea4f2016-02-26 11:57:40 -0600778 {
Vernon Mauery15541322019-03-25 13:33:03 -0700779 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"),
780 Argument::ARGUMENT_VALUE(rfc4122.c_str()));
vishwa1eaea4f2016-02-26 11:57:40 -0600781 }
Vernon Mauery15541322019-03-25 13:33:03 -0700782 for (size_t ind = 0; ind < uuidHexLength; ind += 2)
vishwa1eaea4f2016-02-26 11:57:40 -0600783 {
Vernon Mauery15541322019-03-25 13:33:03 -0700784 char v[3];
785 v[0] = rfc4122[ind];
786 v[1] = rfc4122[ind + 1];
787 v[2] = 0;
788 size_t err;
789 long b;
790 try
Emily Shafferedb8bb02018-09-27 14:50:15 -0700791 {
Vernon Mauery15541322019-03-25 13:33:03 -0700792 b = std::stoul(v, &err, 16);
Emily Shafferedb8bb02018-09-27 14:50:15 -0700793 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500794 catch (const std::exception& e)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500795 {
Vernon Mauery15541322019-03-25 13:33:03 -0700796 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"),
797 Argument::ARGUMENT_VALUE(rfc4122.c_str()));
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500798 }
Vernon Mauery15541322019-03-25 13:33:03 -0700799 // check that exactly two ascii bytes were converted
800 if (err != 2)
801 {
802 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"),
803 Argument::ARGUMENT_VALUE(rfc4122.c_str()));
804 }
805 uuid[uuidBinaryLength - (ind / 2) - 1] = static_cast<uint8_t>(b);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500806 }
Vernon Mauery15541322019-03-25 13:33:03 -0700807 return uuid;
808}
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500809
Vernon Mauery15541322019-03-25 13:33:03 -0700810auto ipmiAppGetDeviceGuid()
811 -> ipmi::RspType<std::array<uint8_t, uuidBinaryLength>>
812{
813 // return a fixed GUID based on /etc/machine-id
814 // This should match the /redfish/v1/Managers/bmc's UUID data
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500815
Vernon Mauery15541322019-03-25 13:33:03 -0700816 // machine specific application ID (for BMC ID)
817 // generated by systemd-id128 -p new as per man page
818 static constexpr sd_id128_t bmcUuidAppId = SD_ID128_MAKE(
819 e0, e1, 73, 76, 64, 61, 47, da, a5, 0c, d0, cc, 64, 12, 45, 78);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500820
Vernon Mauery15541322019-03-25 13:33:03 -0700821 sd_id128_t bmcUuid;
822 // create the UUID from /etc/machine-id via the systemd API
823 sd_id128_get_machine_app_specific(bmcUuidAppId, &bmcUuid);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500824
Vernon Mauery15541322019-03-25 13:33:03 -0700825 char bmcUuidCstr[SD_ID128_STRING_MAX];
826 std::string systemUuid = sd_id128_to_string(bmcUuid, bmcUuidCstr);
827
828 std::array<uint8_t, uuidBinaryLength> uuid = rfc4122ToIpmi(systemUuid);
829 return ipmi::responseSuccess(uuid);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500830}
Chris Austen6caf28b2015-10-13 12:40:40 -0500831
Vernon Mauerycc99ba42019-03-25 13:40:11 -0700832auto ipmiAppGetBtCapabilities()
833 -> ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t>
vishwabmcba0bd5f2015-09-30 16:50:23 +0530834{
Adriana Kobylak88ad8152016-12-13 10:09:08 -0600835 // Per IPMI 2.0 spec, the input and output buffer size must be the max
836 // buffer size minus one byte to allocate space for the length byte.
Vernon Mauerycc99ba42019-03-25 13:40:11 -0700837 constexpr uint8_t nrOutstanding = 0x01;
838 constexpr uint8_t inputBufferSize = MAX_IPMI_BUFFER - 1;
839 constexpr uint8_t outputBufferSize = MAX_IPMI_BUFFER - 1;
840 constexpr uint8_t transactionTime = 0x0A;
841 constexpr uint8_t nrRetries = 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530842
Vernon Mauerycc99ba42019-03-25 13:40:11 -0700843 return ipmi::responseSuccess(nrOutstanding, inputBufferSize,
844 outputBufferSize, transactionTime, nrRetries);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530845}
846
Vernon Maueryb90a5322019-03-25 13:36:55 -0700847auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>>
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600848{
Vernon Maueryb90a5322019-03-25 13:36:55 -0700849 static constexpr auto uuidInterface = "xyz.openbmc_project.Common.UUID";
850 static constexpr auto uuidProperty = "UUID";
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600851
Vernon Maueryb90a5322019-03-25 13:36:55 -0700852 ipmi::Value propValue;
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600853 try
854 {
855 // Get the Inventory object implementing BMC interface
Vernon Maueryb90a5322019-03-25 13:36:55 -0700856 auto busPtr = getSdBus();
Hieu Huynh45aed692022-10-12 10:58:26 +0000857 auto objectInfo = ipmi::getDbusObject(*busPtr, uuidInterface);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600858
859 // Read UUID property value from bmcObject
860 // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Vernon Maueryb90a5322019-03-25 13:36:55 -0700861 propValue =
862 ipmi::getDbusProperty(*busPtr, objectInfo.second, objectInfo.first,
863 uuidInterface, uuidProperty);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600864 }
865 catch (const InternalFailure& e)
866 {
867 log<level::ERR>("Failed in reading BMC UUID property",
Vernon Maueryb90a5322019-03-25 13:36:55 -0700868 entry("INTERFACE=%s", uuidInterface),
869 entry("PROPERTY=%s", uuidProperty));
870 return ipmi::responseUnspecifiedError();
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600871 }
Vernon Maueryb90a5322019-03-25 13:36:55 -0700872 std::array<uint8_t, 16> uuid;
873 std::string rfc4122Uuid = std::get<std::string>(propValue);
874 try
875 {
876 // convert to IPMI format
877 uuid = rfc4122ToIpmi(rfc4122Uuid);
878 }
879 catch (const InvalidArgument& e)
880 {
881 log<level::ERR>("Failed in parsing BMC UUID property",
882 entry("INTERFACE=%s", uuidInterface),
883 entry("PROPERTY=%s", uuidProperty),
884 entry("VALUE=%s", rfc4122Uuid.c_str()));
885 return ipmi::responseUnspecifiedError();
886 }
887 return ipmi::responseSuccess(uuid);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600888}
889
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +0000890/**
891 * @brief set the session state as teardown
892 *
893 * This function is to set the session state to tear down in progress if the
894 * state is active.
895 *
896 * @param[in] busp - Dbus obj
897 * @param[in] service - service name
898 * @param[in] obj - object path
899 *
900 * @return success completion code if it sets the session state to
901 * tearDownInProgress else return the corresponding error completion code.
902 **/
903uint8_t setSessionState(std::shared_ptr<sdbusplus::asio::connection>& busp,
904 const std::string& service, const std::string& obj)
905{
906 try
907 {
908 uint8_t sessionState = std::get<uint8_t>(ipmi::getDbusProperty(
909 *busp, service, obj, session::sessionIntf, "State"));
910
911 if (sessionState == static_cast<uint8_t>(session::State::active))
912 {
913 ipmi::setDbusProperty(
914 *busp, service, obj, session::sessionIntf, "State",
915 static_cast<uint8_t>(session::State::tearDownInProgress));
916 return ipmi::ccSuccess;
917 }
918 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500919 catch (const std::exception& e)
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +0000920 {
921 log<level::ERR>("Failed in getting session state property",
922 entry("service=%s", service.c_str()),
923 entry("object path=%s", obj.c_str()),
924 entry("interface=%s", session::sessionIntf));
925 return ipmi::ccUnspecifiedError;
926 }
927
928 return ipmi::ccInvalidFieldRequest;
929}
930
931ipmi::RspType<> ipmiAppCloseSession(uint32_t reqSessionId,
932 std::optional<uint8_t> requestSessionHandle)
933{
934 auto busp = getSdBus();
935 uint8_t reqSessionHandle =
936 requestSessionHandle.value_or(session::defaultSessionHandle);
937
938 if (reqSessionId == session::sessionZero &&
939 reqSessionHandle == session::defaultSessionHandle)
940 {
941 return ipmi::response(session::ccInvalidSessionId);
942 }
943
944 if (reqSessionId == session::sessionZero &&
945 reqSessionHandle == session::invalidSessionHandle)
946 {
947 return ipmi::response(session::ccInvalidSessionHandle);
948 }
949
950 if (reqSessionId != session::sessionZero &&
951 reqSessionHandle != session::defaultSessionHandle)
952 {
953 return ipmi::response(ipmi::ccInvalidFieldRequest);
954 }
955
956 try
957 {
958 ipmi::ObjectTree objectTree = ipmi::getAllDbusObjects(
959 *busp, session::sessionManagerRootPath, session::sessionIntf);
960
961 for (auto& objectTreeItr : objectTree)
962 {
963 const std::string obj = objectTreeItr.first;
964
965 if (isSessionObjectMatched(obj, reqSessionId, reqSessionHandle))
966 {
967 auto& serviceMap = objectTreeItr.second;
968
969 // Session id and session handle are unique for each session.
970 // Session id and handler are retrived from the object path and
971 // object path will be unique for each session. Checking if
972 // multiple objects exist with same object path under multiple
973 // services.
974 if (serviceMap.size() != 1)
975 {
976 return ipmi::responseUnspecifiedError();
977 }
978
979 auto itr = serviceMap.begin();
980 const std::string service = itr->first;
981 return ipmi::response(setSessionState(busp, service, obj));
982 }
983 }
984 }
Patrick Williams5d82f472022-07-22 19:26:53 -0500985 catch (const sdbusplus::exception_t& e)
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +0000986 {
987 log<level::ERR>("Failed to fetch object from dbus",
988 entry("INTERFACE=%s", session::sessionIntf),
989 entry("ERRMSG=%s", e.what()));
990 return ipmi::responseUnspecifiedError();
991 }
992
993 return ipmi::responseInvalidFieldRequest();
994}
995
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +0000996uint8_t getTotalSessionCount()
997{
Meera-Kattac1789482021-05-18 09:53:26 +0000998 uint8_t count = 0, ch = 0;
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +0000999
1000 while (ch < ipmi::maxIpmiChannels &&
1001 count < session::maxNetworkInstanceSupported)
1002 {
Jayaprakash Mutyala80207e62020-07-04 16:34:15 +00001003 ipmi::ChannelInfo chInfo{};
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001004 ipmi::getChannelInfo(ch, chInfo);
1005 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
1006 ipmi::EChannelMediumType::lan8032)
1007 {
1008 count++;
1009 }
1010 ch++;
1011 }
1012 return count * session::maxSessionCountPerChannel;
1013}
1014
1015/**
1016 * @brief get session info request data.
1017 *
1018 * This function validates the request data and retrive request session id,
1019 * session handle.
1020 *
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301021 * @param[in] ctx - context of current session.
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001022 * @param[in] sessionIndex - request session index
1023 * @param[in] payload - input payload
1024 * @param[in] reqSessionId - unpacked session Id will be asigned
1025 * @param[in] reqSessionHandle - unpacked session handle will be asigned
1026 *
1027 * @return success completion code if request data is valid
1028 * else return the correcponding error completion code.
1029 **/
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301030uint8_t getSessionInfoRequestData(const ipmi::Context::ptr ctx,
1031 const uint8_t sessionIndex,
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001032 ipmi::message::Payload& payload,
1033 uint32_t& reqSessionId,
1034 uint8_t& reqSessionHandle)
1035{
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301036 if ((sessionIndex > session::maxSessionCountPerChannel) &&
1037 (sessionIndex < session::searchSessionByHandle))
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001038 {
1039 return ipmi::ccInvalidFieldRequest;
1040 }
1041
1042 switch (sessionIndex)
1043 {
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301044 case session::searchCurrentSession:
1045
1046 ipmi::ChannelInfo chInfo;
1047 ipmi::getChannelInfo(ctx->channel, chInfo);
1048
1049 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) !=
1050 ipmi::EChannelMediumType::lan8032)
1051 {
1052 return ipmi::ccInvalidFieldRequest;
1053 }
1054
1055 if (!payload.fullyUnpacked())
1056 {
1057 return ipmi::ccReqDataLenInvalid;
1058 }
1059 // Check if current sessionId is 0, sessionId 0 is reserved.
1060 if (ctx->sessionId == session::sessionZero)
1061 {
1062 return session::ccInvalidSessionId;
1063 }
1064 reqSessionId = ctx->sessionId;
1065 break;
1066
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001067 case session::searchSessionByHandle:
1068
1069 if ((payload.unpack(reqSessionHandle)) ||
1070 (!payload.fullyUnpacked()))
1071 {
1072 return ipmi::ccReqDataLenInvalid;
1073 }
1074
1075 if ((reqSessionHandle == session::sessionZero) ||
1076 ((reqSessionHandle & session::multiIntfaceSessionHandleMask) >
1077 session::maxSessionCountPerChannel))
1078 {
1079 return session::ccInvalidSessionHandle;
1080 }
1081 break;
1082
1083 case session::searchSessionById:
1084
1085 if ((payload.unpack(reqSessionId)) || (!payload.fullyUnpacked()))
1086 {
1087 return ipmi::ccReqDataLenInvalid;
1088 }
1089
1090 if (reqSessionId == session::sessionZero)
1091 {
1092 return session::ccInvalidSessionId;
1093 }
1094 break;
1095
1096 default:
1097 if (!payload.fullyUnpacked())
1098 {
1099 return ipmi::ccReqDataLenInvalid;
1100 }
1101 break;
1102 }
1103 return ipmi::ccSuccess;
1104}
1105
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001106uint8_t getSessionState(ipmi::Context::ptr ctx, const std::string& service,
1107 const std::string& objPath, uint8_t& sessionState)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001108{
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001109 boost::system::error_code ec = ipmi::getDbusProperty(
1110 ctx, service, objPath, session::sessionIntf, "State", sessionState);
1111 if (ec)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001112 {
1113 log<level::ERR>("Failed to fetch state property ",
1114 entry("SERVICE=%s", service.c_str()),
1115 entry("OBJECTPATH=%s", objPath.c_str()),
1116 entry("INTERFACE=%s", session::sessionIntf),
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001117 entry("ERRMSG=%s", ec.message().c_str()));
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001118 return ipmi::ccUnspecifiedError;
1119 }
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001120 return ipmi::ccSuccess;
1121}
1122
1123static constexpr uint8_t macAddrLen = 6;
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001124/** Alias SessionDetails - contain the optional information about an
1125 * RMCP+ session.
1126 *
1127 * @param userID - uint6_t session user ID (0-63)
1128 * @param reserved - uint2_t reserved
1129 * @param privilege - uint4_t session privilege (0-5)
1130 * @param reserved - uint4_t reserved
1131 * @param channel - uint4_t session channel number
1132 * @param protocol - uint4_t session protocol
1133 * @param remoteIP - uint32_t remote IP address
1134 * @param macAddr - std::array<uint8_t, 6> mac address
1135 * @param port - uint16_t remote port
1136 */
1137using SessionDetails =
1138 std::tuple<uint2_t, uint6_t, uint4_t, uint4_t, uint4_t, uint4_t, uint32_t,
1139 std::array<uint8_t, macAddrLen>, uint16_t>;
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001140
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001141/** @brief get session details for a given session
1142 *
1143 * @param[in] ctx - ipmi::Context pointer for accessing D-Bus
1144 * @param[in] service - D-Bus service name to fetch details from
1145 * @param[in] objPath - D-Bus object path for session
1146 * @param[out] sessionHandle - return session handle for session
1147 * @param[out] sessionState - return session state for session
1148 * @param[out] details - return a SessionDetails tuple containing other
1149 * session info
1150 * @return - ipmi::Cc success or error code
1151 */
1152ipmi::Cc getSessionDetails(ipmi::Context::ptr ctx, const std::string& service,
1153 const std::string& objPath, uint8_t& sessionHandle,
1154 uint8_t& sessionState, SessionDetails& details)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001155{
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001156 ipmi::PropertyMap sessionProps;
1157 boost::system::error_code ec = ipmi::getAllDbusProperties(
1158 ctx, service, objPath, session::sessionIntf, sessionProps);
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001159
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001160 if (ec)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001161 {
1162 log<level::ERR>("Failed to fetch state property ",
1163 entry("SERVICE=%s", service.c_str()),
1164 entry("OBJECTPATH=%s", objPath.c_str()),
1165 entry("INTERFACE=%s", session::sessionIntf),
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001166 entry("ERRMSG=%s", ec.message().c_str()));
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001167 return ipmi::ccUnspecifiedError;
1168 }
1169
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001170 sessionState = ipmi::mappedVariant<uint8_t>(
1171 sessionProps, "State", static_cast<uint8_t>(session::State::inactive));
1172 if (sessionState == static_cast<uint8_t>(session::State::active))
1173 {
1174 sessionHandle =
1175 ipmi::mappedVariant<uint8_t>(sessionProps, "SessionHandle", 0);
1176 std::get<0>(details) =
1177 ipmi::mappedVariant<uint8_t>(sessionProps, "UserID", 0xff);
1178 // std::get<1>(details) = 0; // (default constructed to 0)
1179 std::get<2>(details) =
1180 ipmi::mappedVariant<uint8_t>(sessionProps, "CurrentPrivilege", 0);
1181 // std::get<3>(details) = 0; // (default constructed to 0)
1182 std::get<4>(details) =
1183 ipmi::mappedVariant<uint8_t>(sessionProps, "ChannelNum", 0xff);
1184 constexpr uint4_t rmcpPlusProtocol = 1;
1185 std::get<5>(details) = rmcpPlusProtocol;
1186 std::get<6>(details) =
1187 ipmi::mappedVariant<uint32_t>(sessionProps, "RemoteIPAddr", 0);
1188 // std::get<7>(details) = {{0}}; // default constructed to all 0
1189 std::get<8>(details) =
1190 ipmi::mappedVariant<uint16_t>(sessionProps, "RemotePort", 0);
1191 }
1192
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001193 return ipmi::ccSuccess;
1194}
1195
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001196ipmi::RspType<uint8_t, // session handle,
1197 uint8_t, // total session count
1198 uint8_t, // active session count
1199 std::optional<SessionDetails>>
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301200 ipmiAppGetSessionInfo(ipmi::Context::ptr ctx, uint8_t sessionIndex,
1201 ipmi::message::Payload& payload)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001202{
1203 uint32_t reqSessionId = 0;
1204 uint8_t reqSessionHandle = session::defaultSessionHandle;
1205 // initializing state to 0xff as 0 represents state as inactive.
1206 uint8_t state = 0xFF;
1207
1208 uint8_t completionCode = getSessionInfoRequestData(
Rajashekar Gade Reddy4d226402019-11-13 17:13:05 +05301209 ctx, sessionIndex, payload, reqSessionId, reqSessionHandle);
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001210
1211 if (completionCode)
1212 {
1213 return ipmi::response(completionCode);
1214 }
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001215 ipmi::ObjectTree objectTree;
1216 boost::system::error_code ec = ipmi::getAllDbusObjects(
1217 ctx, session::sessionManagerRootPath, session::sessionIntf, objectTree);
1218 if (ec)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001219 {
1220 log<level::ERR>("Failed to fetch object from dbus",
1221 entry("INTERFACE=%s", session::sessionIntf),
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001222 entry("ERRMSG=%s", ec.message().c_str()));
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001223 return ipmi::responseUnspecifiedError();
1224 }
1225
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001226 uint8_t totalSessionCount = getTotalSessionCount();
1227 uint8_t activeSessionCount = 0;
1228 uint8_t sessionHandle = session::defaultSessionHandle;
1229 std::optional<SessionDetails> maybeDetails;
1230 uint8_t index = 0;
1231 for (auto& objectTreeItr : objectTree)
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001232 {
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001233 uint32_t sessionId = 0;
1234 std::string objectPath = objectTreeItr.first;
1235
1236 if (!parseCloseSessionInputPayload(objectPath, sessionId,
1237 sessionHandle))
1238 {
1239 continue;
1240 }
1241 index++;
1242 auto& serviceMap = objectTreeItr.second;
1243 auto itr = serviceMap.begin();
1244
1245 if (serviceMap.size() != 1)
1246 {
1247 return ipmi::responseUnspecifiedError();
1248 }
1249
1250 std::string service = itr->first;
1251 uint8_t sessionState = 0;
1252 completionCode =
1253 getSessionState(ctx, service, objectPath, sessionState);
1254 if (completionCode)
1255 {
1256 return ipmi::response(completionCode);
1257 }
1258
1259 if (sessionState == static_cast<uint8_t>(session::State::active))
1260 {
1261 activeSessionCount++;
1262 }
1263
1264 if (index != sessionIndex && reqSessionId != sessionId &&
1265 reqSessionHandle != sessionHandle)
1266 {
1267 continue;
1268 }
1269
1270 SessionDetails details{};
1271 completionCode = getSessionDetails(ctx, service, objectPath,
1272 sessionHandle, state, details);
1273
1274 if (completionCode)
1275 {
1276 return ipmi::response(completionCode);
1277 }
1278 maybeDetails = std::move(details);
Brian Ma61880882022-07-15 09:34:07 +08001279 break;
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001280 }
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001281
1282 if (state == static_cast<uint8_t>(session::State::active) ||
1283 state == static_cast<uint8_t>(session::State::tearDownInProgress))
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001284 {
Vernon Mauerye7e8b812019-10-28 16:00:34 -07001285 return ipmi::responseSuccess(sessionHandle, totalSessionCount,
1286 activeSessionCount, maybeDetails);
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001287 }
1288
1289 return ipmi::responseInvalidFieldRequest();
1290}
1291
Xo Wangf542e8b2017-08-09 15:34:16 -07001292static std::unique_ptr<SysInfoParamStore> sysInfoParamStore;
1293
Xo Wang87651332017-08-11 10:17:59 -07001294static std::string sysInfoReadSystemName()
1295{
1296 // Use the BMC hostname as the "System Name."
1297 char hostname[HOST_NAME_MAX + 1] = {};
1298 if (gethostname(hostname, HOST_NAME_MAX) != 0)
1299 {
1300 perror("System info parameter: system name");
1301 }
1302 return hostname;
1303}
1304
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001305static constexpr uint8_t paramRevision = 0x11;
1306static constexpr size_t configParameterLength = 16;
Xo Wangf542e8b2017-08-09 15:34:16 -07001307
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001308static constexpr size_t smallChunkSize = 14;
1309static constexpr size_t fullChunkSize = 16;
Jia, chunhui449f2162019-09-11 16:51:51 +08001310static constexpr uint8_t progressMask = 0x3;
Xo Wangf542e8b2017-08-09 15:34:16 -07001311
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001312static constexpr uint8_t setComplete = 0x0;
1313static constexpr uint8_t setInProgress = 0x1;
1314static constexpr uint8_t commitWrite = 0x2;
1315static uint8_t transferStatus = setComplete;
1316
Jia, chunhui449f2162019-09-11 16:51:51 +08001317static constexpr uint8_t configDataOverhead = 2;
1318
1319// For EFI based system, 256 bytes is recommended.
1320static constexpr size_t maxBytesPerParameter = 256;
1321
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001322namespace ipmi
1323{
1324constexpr Cc ccParmNotSupported = 0x80;
Jia, chunhui449f2162019-09-11 16:51:51 +08001325constexpr Cc ccSetInProgressActive = 0x81;
1326constexpr Cc ccSystemInfoParameterSetReadOnly = 0x82;
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001327
1328static inline auto responseParmNotSupported()
1329{
1330 return response(ccParmNotSupported);
Xo Wangf542e8b2017-08-09 15:34:16 -07001331}
Jia, chunhui449f2162019-09-11 16:51:51 +08001332static inline auto responseSetInProgressActive()
1333{
1334 return response(ccSetInProgressActive);
1335}
1336static inline auto responseSystemInfoParameterSetReadOnly()
1337{
1338 return response(ccSystemInfoParameterSetReadOnly);
1339}
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001340} // namespace ipmi
Xo Wangf542e8b2017-08-09 15:34:16 -07001341
Jia, chunhui449f2162019-09-11 16:51:51 +08001342ipmi::RspType<uint8_t, // Parameter revision
1343 std::optional<uint8_t>, // data1 / setSelector / ProgressStatus
1344 std::optional<std::vector<uint8_t>>> // data2-17
jayaprakash Mutyalac2566a92020-04-23 21:18:35 +00001345 ipmiAppGetSystemInfo(uint7_t reserved, bool getRevision,
1346 uint8_t paramSelector, uint8_t setSelector,
1347 uint8_t BlockSelector)
Xo Wangf542e8b2017-08-09 15:34:16 -07001348{
Snehalatha Va5ae7722020-05-02 18:18:57 +00001349 if (reserved || (paramSelector >= invalidParamSelectorStart &&
1350 paramSelector <= invalidParamSelectorEnd))
jayaprakash Mutyalac2566a92020-04-23 21:18:35 +00001351 {
1352 return ipmi::responseInvalidFieldRequest();
1353 }
Snehalatha Va5ae7722020-05-02 18:18:57 +00001354 if ((paramSelector >= oemCmdStart) && (paramSelector <= oemCmdEnd))
1355 {
1356 return ipmi::responseParmNotSupported();
1357 }
jayaprakash Mutyalac2566a92020-04-23 21:18:35 +00001358 if (getRevision)
Xo Wangf542e8b2017-08-09 15:34:16 -07001359 {
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001360 return ipmi::responseSuccess(paramRevision, std::nullopt, std::nullopt);
Xo Wangf542e8b2017-08-09 15:34:16 -07001361 }
1362
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001363 if (paramSelector == 0)
Xo Wangf542e8b2017-08-09 15:34:16 -07001364 {
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001365 return ipmi::responseSuccess(paramRevision, transferStatus,
1366 std::nullopt);
Xo Wangf542e8b2017-08-09 15:34:16 -07001367 }
1368
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001369 if (BlockSelector != 0) // 00h if parameter does not require a block number
Xo Wangf542e8b2017-08-09 15:34:16 -07001370 {
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001371 return ipmi::responseParmNotSupported();
Xo Wangf542e8b2017-08-09 15:34:16 -07001372 }
1373
1374 if (sysInfoParamStore == nullptr)
1375 {
1376 sysInfoParamStore = std::make_unique<SysInfoParamStore>();
Xo Wang87651332017-08-11 10:17:59 -07001377 sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME,
1378 sysInfoReadSystemName);
Xo Wangf542e8b2017-08-09 15:34:16 -07001379 }
1380
1381 // Parameters other than Set In Progress are assumed to be strings.
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001382 std::tuple<bool, std::string> ret =
1383 sysInfoParamStore->lookup(paramSelector);
1384 bool found = std::get<0>(ret);
Xo Wangf542e8b2017-08-09 15:34:16 -07001385 if (!found)
1386 {
Snehalatha Va5ae7722020-05-02 18:18:57 +00001387 return ipmi::responseSensorInvalid();
Xo Wangf542e8b2017-08-09 15:34:16 -07001388 }
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001389 std::string& paramString = std::get<1>(ret);
Jia, chunhui449f2162019-09-11 16:51:51 +08001390 std::vector<uint8_t> configData;
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001391 size_t count = 0;
1392 if (setSelector == 0)
Jia, chunhui449f2162019-09-11 16:51:51 +08001393 { // First chunk has only 14 bytes.
1394 configData.emplace_back(0); // encoding
1395 configData.emplace_back(paramString.length()); // string length
1396 count = std::min(paramString.length(), smallChunkSize);
1397 configData.resize(count + configDataOverhead);
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001398 std::copy_n(paramString.begin(), count,
Snehalatha Va5ae7722020-05-02 18:18:57 +00001399 configData.begin() + configDataOverhead); // 14 bytes chunk
1400
1401 // Append zero's to remaining bytes
1402 if (configData.size() < configParameterLength)
1403 {
1404 std::fill_n(std::back_inserter(configData),
1405 configParameterLength - configData.size(), 0x00);
1406 }
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001407 }
1408 else
Xo Wangf542e8b2017-08-09 15:34:16 -07001409 {
Jia, chunhui449f2162019-09-11 16:51:51 +08001410 size_t offset = (setSelector * fullChunkSize) - configDataOverhead;
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001411 if (offset >= paramString.length())
1412 {
1413 return ipmi::responseParmOutOfRange();
1414 }
Jia, chunhui449f2162019-09-11 16:51:51 +08001415 count = std::min(paramString.length() - offset, fullChunkSize);
1416 configData.resize(count);
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001417 std::copy_n(paramString.begin() + offset, count,
1418 configData.begin()); // 16 bytes chunk
Xo Wangf542e8b2017-08-09 15:34:16 -07001419 }
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001420 return ipmi::responseSuccess(paramRevision, setSelector, configData);
Xo Wangf542e8b2017-08-09 15:34:16 -07001421}
1422
Jia, chunhui449f2162019-09-11 16:51:51 +08001423ipmi::RspType<> ipmiAppSetSystemInfo(uint8_t paramSelector, uint8_t data1,
1424 std::vector<uint8_t> configData)
1425{
jayaprakash Mutyala3c5e4132020-04-27 23:00:05 +00001426 if (paramSelector >= invalidParamSelectorStart &&
1427 paramSelector <= invalidParamSelectorEnd)
1428 {
1429 return ipmi::responseInvalidFieldRequest();
1430 }
1431 if ((paramSelector >= oemCmdStart) && (paramSelector <= oemCmdEnd))
1432 {
1433 return ipmi::responseParmNotSupported();
1434 }
1435
Jia, chunhui449f2162019-09-11 16:51:51 +08001436 if (paramSelector == 0)
1437 {
1438 // attempt to set the 'set in progress' value (in parameter #0)
1439 // when not in the set complete state.
1440 if ((transferStatus != setComplete) && (data1 == setInProgress))
1441 {
1442 return ipmi::responseSetInProgressActive();
1443 }
1444 // only following 2 states are supported
1445 if (data1 > setInProgress)
1446 {
1447 phosphor::logging::log<phosphor::logging::level::ERR>(
1448 "illegal SetInProgress status");
1449 return ipmi::responseInvalidFieldRequest();
1450 }
1451
1452 transferStatus = data1 & progressMask;
1453 return ipmi::responseSuccess();
1454 }
1455
1456 if (configData.size() > configParameterLength)
1457 {
1458 return ipmi::responseInvalidFieldRequest();
1459 }
1460
jayaprakash Mutyala3c5e4132020-04-27 23:00:05 +00001461 // Append zero's to remaining bytes
1462 if (configData.size() < configParameterLength)
1463 {
1464 fill_n(back_inserter(configData),
1465 (configParameterLength - configData.size()), 0x00);
1466 }
1467
Jia, chunhui449f2162019-09-11 16:51:51 +08001468 if (!sysInfoParamStore)
1469 {
1470 sysInfoParamStore = std::make_unique<SysInfoParamStore>();
1471 sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME,
1472 sysInfoReadSystemName);
1473 }
1474
1475 // lookup
1476 std::tuple<bool, std::string> ret =
1477 sysInfoParamStore->lookup(paramSelector);
1478 bool found = std::get<0>(ret);
1479 std::string& paramString = std::get<1>(ret);
1480 if (!found)
1481 {
1482 // parameter does not exist. Init new
1483 paramString = "";
1484 }
1485
1486 uint8_t setSelector = data1;
1487 size_t count = 0;
1488 if (setSelector == 0) // First chunk has only 14 bytes.
1489 {
1490 size_t stringLen = configData.at(1); // string length
1491 // maxBytesPerParamter is 256. It will always be greater than stringLen
1492 // (unit8_t) if maxBytes changes in future, then following line is
1493 // needed.
1494 // stringLen = std::min(stringLen, maxBytesPerParameter);
1495 count = std::min(stringLen, smallChunkSize);
1496 count = std::min(count, configData.size());
1497 paramString.resize(stringLen); // reserve space
1498 std::copy_n(configData.begin() + configDataOverhead, count,
1499 paramString.begin());
1500 }
1501 else
1502 {
1503 size_t offset = (setSelector * fullChunkSize) - configDataOverhead;
1504 if (offset >= paramString.length())
1505 {
1506 return ipmi::responseParmOutOfRange();
1507 }
1508 count = std::min(paramString.length() - offset, configData.size());
1509 std::copy_n(configData.begin(), count, paramString.begin() + offset);
1510 }
1511 sysInfoParamStore->update(paramSelector, paramString);
1512 return ipmi::responseSuccess();
1513}
1514
Yong Libd0503a2019-08-22 17:17:17 +08001515#ifdef ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301516inline std::vector<uint8_t> convertStringToData(const std::string& command)
1517{
1518 std::istringstream iss(command);
1519 std::string token;
1520 std::vector<uint8_t> dataValue;
1521 while (std::getline(iss, token, ' '))
1522 {
1523 dataValue.emplace_back(
1524 static_cast<uint8_t>(std::stoul(token, nullptr, base_16)));
1525 }
1526 return dataValue;
1527}
1528
1529static bool populateI2CMasterWRWhitelist()
1530{
1531 nlohmann::json data = nullptr;
1532 std::ifstream jsonFile(i2cMasterWRWhitelistFile);
1533
1534 if (!jsonFile.good())
1535 {
1536 log<level::WARNING>("i2c white list file not found!",
1537 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile));
1538 return false;
1539 }
1540
1541 try
1542 {
1543 data = nlohmann::json::parse(jsonFile, nullptr, false);
1544 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001545 catch (const nlohmann::json::parse_error& e)
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301546 {
1547 log<level::ERR>("Corrupted i2c white list config file",
1548 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile),
1549 entry("MSG: %s", e.what()));
1550 return false;
1551 }
1552
1553 try
1554 {
1555 // Example JSON Structure format
1556 // "filters": [
1557 // {
1558 // "Description": "Allow full read - ignore first byte write value
1559 // for 0x40 to 0x4F",
1560 // "busId": "0x01",
1561 // "slaveAddr": "0x40",
1562 // "slaveAddrMask": "0x0F",
1563 // "command": "0x00",
1564 // "commandMask": "0xFF"
1565 // },
1566 // {
1567 // "Description": "Allow full read - first byte match 0x05 and
1568 // ignore second byte",
1569 // "busId": "0x01",
1570 // "slaveAddr": "0x57",
1571 // "slaveAddrMask": "0x00",
1572 // "command": "0x05 0x00",
1573 // "commandMask": "0x00 0xFF"
1574 // },]
1575
1576 nlohmann::json filters = data[filtersStr].get<nlohmann::json>();
1577 std::vector<i2cMasterWRWhitelist>& whitelist = getWRWhitelist();
1578 for (const auto& it : filters.items())
1579 {
1580 nlohmann::json filter = it.value();
1581 if (filter.is_null())
1582 {
1583 log<level::ERR>(
1584 "Corrupted I2C master write read whitelist config file",
1585 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile));
1586 return false;
1587 }
1588 const std::vector<uint8_t>& writeData =
1589 convertStringToData(filter[cmdStr].get<std::string>());
1590 const std::vector<uint8_t>& writeDataMask =
1591 convertStringToData(filter[cmdMaskStr].get<std::string>());
1592 if (writeDataMask.size() != writeData.size())
1593 {
1594 log<level::ERR>("I2C master write read whitelist filter "
1595 "mismatch for command & mask size");
1596 return false;
1597 }
1598 whitelist.push_back(
1599 {static_cast<uint8_t>(std::stoul(
1600 filter[busIdStr].get<std::string>(), nullptr, base_16)),
1601 static_cast<uint8_t>(
1602 std::stoul(filter[slaveAddrStr].get<std::string>(),
1603 nullptr, base_16)),
1604 static_cast<uint8_t>(
1605 std::stoul(filter[slaveAddrMaskStr].get<std::string>(),
1606 nullptr, base_16)),
1607 writeData, writeDataMask});
1608 }
1609 if (whitelist.size() != filters.size())
1610 {
1611 log<level::ERR>(
1612 "I2C master write read whitelist filter size mismatch");
1613 return false;
1614 }
1615 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001616 catch (const std::exception& e)
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301617 {
1618 log<level::ERR>("I2C master write read whitelist unexpected exception",
1619 entry("ERROR=%s", e.what()));
1620 return false;
1621 }
1622 return true;
1623}
1624
1625static inline bool isWriteDataWhitelisted(const std::vector<uint8_t>& data,
1626 const std::vector<uint8_t>& dataMask,
1627 const std::vector<uint8_t>& writeData)
1628{
1629 std::vector<uint8_t> processedDataBuf(data.size());
1630 std::vector<uint8_t> processedReqBuf(dataMask.size());
1631 std::transform(writeData.begin(), writeData.end(), dataMask.begin(),
1632 processedReqBuf.begin(), std::bit_or<uint8_t>());
1633 std::transform(data.begin(), data.end(), dataMask.begin(),
1634 processedDataBuf.begin(), std::bit_or<uint8_t>());
1635
1636 return (processedDataBuf == processedReqBuf);
1637}
1638
1639static bool isCmdWhitelisted(uint8_t busId, uint8_t slaveAddr,
1640 std::vector<uint8_t>& writeData)
1641{
1642 std::vector<i2cMasterWRWhitelist>& whiteList = getWRWhitelist();
1643 for (const auto& wlEntry : whiteList)
1644 {
1645 if ((busId == wlEntry.busId) &&
1646 ((slaveAddr | wlEntry.slaveAddrMask) ==
1647 (wlEntry.slaveAddr | wlEntry.slaveAddrMask)))
1648 {
1649 const std::vector<uint8_t>& dataMask = wlEntry.dataMask;
1650 // Skip as no-match, if requested write data is more than the
1651 // write data mask size
1652 if (writeData.size() > dataMask.size())
1653 {
1654 continue;
1655 }
1656 if (isWriteDataWhitelisted(wlEntry.data, dataMask, writeData))
1657 {
1658 return true;
1659 }
1660 }
1661 }
1662 return false;
1663}
Yong Libd0503a2019-08-22 17:17:17 +08001664#else
1665static bool populateI2CMasterWRWhitelist()
1666{
1667 log<level::INFO>(
1668 "I2C_WHITELIST_CHECK is disabled, do not populate whitelist");
1669 return true;
1670}
1671#endif // ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301672
1673/** @brief implements master write read IPMI command which can be used for
1674 * low-level I2C/SMBus write, read or write-read access
1675 * @param isPrivateBus -to indicate private bus usage
1676 * @param busId - bus id
1677 * @param channelNum - channel number
1678 * @param reserved - skip 1 bit
1679 * @param slaveAddr - slave address
1680 * @param read count - number of bytes to be read
1681 * @param writeData - data to be written
1682 *
1683 * @returns IPMI completion code plus response data
1684 * - readData - i2c response data
1685 */
1686ipmi::RspType<std::vector<uint8_t>>
Willy Tu11d68892022-01-20 10:37:34 -08001687 ipmiMasterWriteRead([[maybe_unused]] bool isPrivateBus, uint3_t busId,
1688 [[maybe_unused]] uint4_t channelNum, bool reserved,
1689 uint7_t slaveAddr, uint8_t readCount,
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301690 std::vector<uint8_t> writeData)
1691{
Jayaprakash Mutyalac2af98b2021-09-14 09:19:11 +00001692 if (reserved)
1693 {
1694 return ipmi::responseInvalidFieldRequest();
1695 }
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301696 if (readCount > maxIPMIWriteReadSize)
1697 {
1698 log<level::ERR>("Master write read command: Read count exceeds limit");
1699 return ipmi::responseParmOutOfRange();
1700 }
1701 const size_t writeCount = writeData.size();
1702 if (!readCount && !writeCount)
1703 {
1704 log<level::ERR>("Master write read command: Read & write count are 0");
1705 return ipmi::responseInvalidFieldRequest();
1706 }
Yong Libd0503a2019-08-22 17:17:17 +08001707#ifdef ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301708 if (!isCmdWhitelisted(static_cast<uint8_t>(busId),
1709 static_cast<uint8_t>(slaveAddr), writeData))
1710 {
1711 log<level::ERR>("Master write read request blocked!",
1712 entry("BUS=%d", static_cast<uint8_t>(busId)),
1713 entry("ADDR=0x%x", static_cast<uint8_t>(slaveAddr)));
1714 return ipmi::responseInvalidFieldRequest();
1715 }
Yong Libd0503a2019-08-22 17:17:17 +08001716#endif // ENABLE_I2C_WHITELIST_CHECK
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301717 std::vector<uint8_t> readBuf(readCount);
1718 std::string i2cBus =
1719 "/dev/i2c-" + std::to_string(static_cast<uint8_t>(busId));
1720
Yong Li7dc4ac02019-08-23 17:44:32 +08001721 ipmi::Cc ret = ipmi::i2cWriteRead(i2cBus, static_cast<uint8_t>(slaveAddr),
1722 writeData, readBuf);
1723 if (ret != ipmi::ccSuccess)
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301724 {
Yong Li7dc4ac02019-08-23 17:44:32 +08001725 return ipmi::response(ret);
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301726 }
1727 return ipmi::responseSuccess(readBuf);
1728}
1729
Chris Austen6caf28b2015-10-13 12:40:40 -05001730void register_netfn_app_functions()
vishwabmcba0bd5f2015-09-30 16:50:23 +05301731{
Vernon Mauery86a50822019-03-25 13:11:36 -07001732 // <Get Device ID>
1733 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1734 ipmi::app::cmdGetDeviceId, ipmi::Privilege::User,
1735 ipmiAppGetDeviceId);
1736
Tom05732372016-09-06 17:21:23 +05301737 // <Get BT Interface Capabilities>
Vernon Mauerycc99ba42019-03-25 13:40:11 -07001738 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1739 ipmi::app::cmdGetBtIfaceCapabilities,
1740 ipmi::Privilege::User, ipmiAppGetBtCapabilities);
Chris Austen6caf28b2015-10-13 12:40:40 -05001741
Tom05732372016-09-06 17:21:23 +05301742 // <Reset Watchdog Timer>
Vernon Mauery11df4f62019-03-25 14:17:54 -07001743 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1744 ipmi::app::cmdResetWatchdogTimer,
1745 ipmi::Privilege::Operator, ipmiAppResetWatchdogTimer);
Chris Austen6caf28b2015-10-13 12:40:40 -05001746
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001747 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
AppaRao Puli5a98ea62019-11-10 21:15:02 +05301748 ipmi::app::cmdGetSessionInfo, ipmi::Privilege::User,
1749 ipmiAppGetSessionInfo);
Rajashekar Gade Reddyf71444d2019-07-25 15:12:17 +00001750
Tom05732372016-09-06 17:21:23 +05301751 // <Set Watchdog Timer>
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +00001752 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1753 ipmi::app::cmdSetWatchdogTimer,
1754 ipmi::Privilege::Operator, ipmiSetWatchdogTimer);
Chris Austen6caf28b2015-10-13 12:40:40 -05001755
Rajashekar Gade Reddye7023922019-07-10 16:54:55 +00001756 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1757 ipmi::app::cmdCloseSession, ipmi::Privilege::Callback,
1758 ipmiAppCloseSession);
1759
William A. Kennington III73f44512018-02-09 15:28:46 -08001760 // <Get Watchdog Timer>
Deepak Kumar Sahucfae9482019-05-20 14:58:58 +00001761 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
AppaRao Puli5a98ea62019-11-10 21:15:02 +05301762 ipmi::app::cmdGetWatchdogTimer, ipmi::Privilege::User,
1763 ipmiGetWatchdogTimer);
William A. Kennington III73f44512018-02-09 15:28:46 -08001764
Tom05732372016-09-06 17:21:23 +05301765 // <Get Self Test Results>
Vernon Maueryb84a5282019-03-25 13:39:03 -07001766 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1767 ipmi::app::cmdGetSelfTestResults,
1768 ipmi::Privilege::User, ipmiAppGetSelfTestResults);
Nan Li41fa24a2016-11-10 20:12:37 +08001769
Tom05732372016-09-06 17:21:23 +05301770 // <Get Device GUID>
Vernon Mauery15541322019-03-25 13:33:03 -07001771 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1772 ipmi::app::cmdGetDeviceGuid, ipmi::Privilege::User,
1773 ipmiAppGetDeviceGuid);
Adriana Kobylakd100ee52015-10-20 17:02:37 -05001774
Tom05732372016-09-06 17:21:23 +05301775 // <Set ACPI Power State>
Deepak Kumar Sahu520c1312019-05-17 18:14:09 +00001776 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1777 ipmi::app::cmdSetAcpiPowerState,
1778 ipmi::Privilege::Admin, ipmiSetAcpiPowerState);
Yong Li18d77262018-10-09 01:59:45 +08001779 // <Get ACPI Power State>
Deepak Kumar Sahu4e6d2572019-05-07 19:53:37 +00001780 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1781 ipmi::app::cmdGetAcpiPowerState,
AppaRao Puli5a98ea62019-11-10 21:15:02 +05301782 ipmi::Privilege::User, ipmiGetAcpiPowerState);
Yong Li18d77262018-10-09 01:59:45 +08001783
Richard Marian Thomaiyar84bf9be2019-04-26 22:59:16 +05301784 // Note: For security reason, this command will be registered only when
1785 // there are proper I2C Master write read whitelist
1786 if (populateI2CMasterWRWhitelist())
1787 {
1788 // Note: For security reasons, registering master write read as admin
1789 // privilege command, even though IPMI 2.0 specification allows it as
1790 // operator privilege.
1791 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1792 ipmi::app::cmdMasterWriteRead,
1793 ipmi::Privilege::Admin, ipmiMasterWriteRead);
1794 }
1795
Marri Devender Rao5e007a52018-01-08 06:18:36 -06001796 // <Get System GUID Command>
Vernon Maueryb90a5322019-03-25 13:36:55 -07001797 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1798 ipmi::app::cmdGetSystemGuid, ipmi::Privilege::User,
1799 ipmiAppGetSystemGuid);
Tom Joseph7cbe2282018-03-21 21:17:33 +05301800
1801 // <Get Channel Cipher Suites Command>
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +00001802 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1803 ipmi::app::cmdGetChannelCipherSuites,
Vernon Mauery79b4eea2019-11-07 09:51:39 -08001804 ipmi::Privilege::None, getChannelCipherSuites);
Vernon Maueryd2a57de2019-03-25 12:45:28 -07001805
Xo Wangf542e8b2017-08-09 15:34:16 -07001806 // <Get System Info Command>
Jia, chunhui98b43ba2019-09-05 15:54:23 +08001807 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1808 ipmi::app::cmdGetSystemInfoParameters,
1809 ipmi::Privilege::User, ipmiAppGetSystemInfo);
Jia, chunhui449f2162019-09-11 16:51:51 +08001810 // <Set System Info Command>
1811 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1812 ipmi::app::cmdSetSystemInfoParameters,
1813 ipmi::Privilege::Admin, ipmiAppSetSystemInfo);
vishwabmcba0bd5f2015-09-30 16:50:23 +05301814 return;
1815}