xref: /openbmc/phosphor-host-ipmid/apphandler.cpp (revision a6c307a84fe43679ece859789666cca4c391cd38)
15d214202SPotin Lai #include "config.h"
25d214202SPotin Lai 
30b02be92SPatrick Venture #include <arpa/inet.h>
484bf9be5SRichard Marian Thomaiyar #include <fcntl.h>
587651333SXo Wang #include <limits.h>
684bf9be5SRichard Marian Thomaiyar #include <linux/i2c-dev.h>
784bf9be5SRichard Marian Thomaiyar #include <linux/i2c.h>
884bf9be5SRichard Marian Thomaiyar #include <sys/ioctl.h>
984bf9be5SRichard Marian Thomaiyar #include <sys/stat.h>
1084bf9be5SRichard Marian Thomaiyar #include <sys/types.h>
110b02be92SPatrick Venture #include <systemd/sd-bus.h>
1287651333SXo Wang #include <unistd.h>
130b02be92SPatrick Venture 
140120b680SVernon Mauery #include <app/channel.hpp>
150120b680SVernon Mauery #include <app/watchdog.hpp>
160120b680SVernon Mauery #include <apphandler.hpp>
17fbc6c9d7SPatrick Williams #include <ipmid/api.hpp>
18fbc6c9d7SPatrick Williams #include <ipmid/sessiondef.hpp>
19fbc6c9d7SPatrick Williams #include <ipmid/sessionhelper.hpp>
20fbc6c9d7SPatrick Williams #include <ipmid/types.hpp>
21fbc6c9d7SPatrick Williams #include <ipmid/utils.hpp>
22fbc6c9d7SPatrick Williams #include <nlohmann/json.hpp>
23fbc6c9d7SPatrick Williams #include <phosphor-logging/elog-errors.hpp>
2424fffdc8SGeorge Liu #include <phosphor-logging/lg2.hpp>
25fbc6c9d7SPatrick Williams #include <sdbusplus/message/types.hpp>
26fbc6c9d7SPatrick Williams #include <sys_info_param.hpp>
27fbc6c9d7SPatrick Williams #include <xyz/openbmc_project/Common/error.hpp>
28fbc6c9d7SPatrick Williams #include <xyz/openbmc_project/Control/Power/ACPIPowerState/server.hpp>
29fbc6c9d7SPatrick Williams #include <xyz/openbmc_project/Software/Activation/server.hpp>
30fbc6c9d7SPatrick Williams #include <xyz/openbmc_project/Software/Version/server.hpp>
31fbc6c9d7SPatrick Williams #include <xyz/openbmc_project/State/BMC/server.hpp>
32fbc6c9d7SPatrick Williams 
33fbc6c9d7SPatrick Williams #include <algorithm>
343a5071a9SPatrick Venture #include <array>
35886d6840SWilly Tu #include <charconv>
363a5071a9SPatrick Venture #include <cstddef>
370120b680SVernon Mauery #include <cstdint>
38bdda8008SVernon Mauery #include <filesystem>
393a5071a9SPatrick Venture #include <fstream>
403a5071a9SPatrick Venture #include <memory>
415d214202SPotin Lai #include <regex>
423a5071a9SPatrick Venture #include <string>
43886d6840SWilly Tu #include <string_view>
443a5071a9SPatrick Venture #include <tuple>
453a5071a9SPatrick Venture #include <vector>
46b8e9955dSRatan Gupta 
4798a23840SMatthew Barth extern sd_bus* bus;
4898a23840SMatthew Barth 
49ba19c184SAlexander Amelkin constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC";
50ba19c184SAlexander Amelkin constexpr auto bmc_state_property = "CurrentBMCState";
51a809fa55SThang Tran constexpr auto versionPurposeHostEnd = ".Host";
525e007a5dSMarri Devender Rao 
53744398dcSNagaraju Goruganti static constexpr auto redundancyIntf =
54744398dcSNagaraju Goruganti     "xyz.openbmc_project.Software.RedundancyPriority";
550b02be92SPatrick Venture static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version";
56744398dcSNagaraju Goruganti static constexpr auto activationIntf =
57744398dcSNagaraju Goruganti     "xyz.openbmc_project.Software.Activation";
58744398dcSNagaraju Goruganti static constexpr auto softwareRoot = "/xyz/openbmc_project/software";
59744398dcSNagaraju Goruganti 
605087b075SGeorge Liu void registerNetFnAppFunctions() __attribute__((constructor));
6198a23840SMatthew Barth 
62b8e9955dSRatan Gupta using namespace phosphor::logging;
63523e2d1bSWilly Tu using namespace sdbusplus::error::xyz::openbmc_project::common;
64523e2d1bSWilly Tu using Version = sdbusplus::server::xyz::openbmc_project::software::Version;
65744398dcSNagaraju Goruganti using Activation =
66523e2d1bSWilly Tu     sdbusplus::server::xyz::openbmc_project::software::Activation;
67523e2d1bSWilly Tu using BMC = sdbusplus::server::xyz::openbmc_project::state::BMC;
68185b9f8bSVernon Mauery namespace fs = std::filesystem;
69b8e9955dSRatan Gupta 
70bd0503a7SYong Li #ifdef ENABLE_I2C_WHITELIST_CHECK
7184bf9be5SRichard Marian Thomaiyar typedef struct
7284bf9be5SRichard Marian Thomaiyar {
7384bf9be5SRichard Marian Thomaiyar     uint8_t busId;
7468d9d405SMatt Simmering     uint8_t targetAddr;
7568d9d405SMatt Simmering     uint8_t targetAddrMask;
7684bf9be5SRichard Marian Thomaiyar     std::vector<uint8_t> data;
7784bf9be5SRichard Marian Thomaiyar     std::vector<uint8_t> dataMask;
7868d9d405SMatt Simmering } i2cControllerWRAllowlist;
7984bf9be5SRichard Marian Thomaiyar 
getWRAllowlist()8068d9d405SMatt Simmering static std::vector<i2cControllerWRAllowlist>& getWRAllowlist()
8184bf9be5SRichard Marian Thomaiyar {
8268d9d405SMatt Simmering     static std::vector<i2cControllerWRAllowlist> wrAllowlist;
8368d9d405SMatt Simmering     return wrAllowlist;
8484bf9be5SRichard Marian Thomaiyar }
8584bf9be5SRichard Marian Thomaiyar 
8668d9d405SMatt Simmering static constexpr const char* i2cControllerWRAllowlistFile =
8784bf9be5SRichard Marian Thomaiyar     "/usr/share/ipmi-providers/master_write_read_white_list.json";
8884bf9be5SRichard Marian Thomaiyar 
8984bf9be5SRichard Marian Thomaiyar static constexpr const char* filtersStr = "filters";
9084bf9be5SRichard Marian Thomaiyar static constexpr const char* busIdStr = "busId";
9168d9d405SMatt Simmering static constexpr const char* targetAddrStr = "slaveAddr";
9268d9d405SMatt Simmering static constexpr const char* targetAddrMaskStr = "slaveAddrMask";
9384bf9be5SRichard Marian Thomaiyar static constexpr const char* cmdStr = "command";
9484bf9be5SRichard Marian Thomaiyar static constexpr const char* cmdMaskStr = "commandMask";
9584bf9be5SRichard Marian Thomaiyar static constexpr int base_16 = 16;
96bd0503a7SYong Li #endif // ENABLE_I2C_WHITELIST_CHECK
973c5e413bSjayaprakash Mutyala static constexpr uint8_t oemCmdStart = 192;
983c5e413bSjayaprakash Mutyala static constexpr uint8_t invalidParamSelectorStart = 8;
993c5e413bSjayaprakash Mutyala static constexpr uint8_t invalidParamSelectorEnd = 191;
10084bf9be5SRichard Marian Thomaiyar 
101744398dcSNagaraju Goruganti /**
102744398dcSNagaraju Goruganti  * @brief Returns the Version info from primary s/w object
103744398dcSNagaraju Goruganti  *
104744398dcSNagaraju Goruganti  * Get the Version info from the active s/w object which is having high
105744398dcSNagaraju Goruganti  * "Priority" value(a smaller number is a higher priority) and "Purpose"
106744398dcSNagaraju Goruganti  * is "BMC" from the list of all s/w objects those are implementing
107744398dcSNagaraju Goruganti  * RedundancyPriority interface from the given softwareRoot path.
108744398dcSNagaraju Goruganti  *
109744398dcSNagaraju Goruganti  * @return On success returns the Version info from primary s/w object.
110744398dcSNagaraju Goruganti  *
111744398dcSNagaraju Goruganti  */
getActiveSoftwareVersionInfo(ipmi::Context::ptr ctx)112ea1c401cSVernon Mauery std::string getActiveSoftwareVersionInfo(ipmi::Context::ptr ctx)
113744398dcSNagaraju Goruganti {
114744398dcSNagaraju Goruganti     std::string revision{};
11586a5082fSVernon Mauery     ipmi::ObjectTree objectTree;
11686a5082fSVernon Mauery     try
117744398dcSNagaraju Goruganti     {
1181318a5edSPatrick Williams         objectTree =
1191318a5edSPatrick Williams             ipmi::getAllDbusObjects(*ctx->bus, softwareRoot, redundancyIntf);
12086a5082fSVernon Mauery     }
1215d82f474SPatrick Williams     catch (const sdbusplus::exception_t& e)
12286a5082fSVernon Mauery     {
12324fffdc8SGeorge Liu         lg2::error("Failed to fetch redundancy object from dbus, "
12424fffdc8SGeorge Liu                    "interface: {INTERFACE},  error: {ERROR}",
12524fffdc8SGeorge Liu                    "INTERFACE", redundancyIntf, "ERROR", e);
126744398dcSNagaraju Goruganti         elog<InternalFailure>();
127744398dcSNagaraju Goruganti     }
128744398dcSNagaraju Goruganti 
129744398dcSNagaraju Goruganti     auto objectFound = false;
130744398dcSNagaraju Goruganti     for (auto& softObject : objectTree)
131744398dcSNagaraju Goruganti     {
1321318a5edSPatrick Williams         auto service =
1331318a5edSPatrick Williams             ipmi::getService(*ctx->bus, redundancyIntf, softObject.first);
1341318a5edSPatrick Williams         auto objValueTree =
1351318a5edSPatrick Williams             ipmi::getManagedObjects(*ctx->bus, service, softwareRoot);
136744398dcSNagaraju Goruganti 
137744398dcSNagaraju Goruganti         auto minPriority = 0xFF;
138744398dcSNagaraju Goruganti         for (const auto& objIter : objValueTree)
139744398dcSNagaraju Goruganti         {
140744398dcSNagaraju Goruganti             try
141744398dcSNagaraju Goruganti             {
142744398dcSNagaraju Goruganti                 auto& intfMap = objIter.second;
143744398dcSNagaraju Goruganti                 auto& redundancyPriorityProps = intfMap.at(redundancyIntf);
144744398dcSNagaraju Goruganti                 auto& versionProps = intfMap.at(versionIntf);
145744398dcSNagaraju Goruganti                 auto& activationProps = intfMap.at(activationIntf);
146f442e119SVernon Mauery                 auto priority =
147f442e119SVernon Mauery                     std::get<uint8_t>(redundancyPriorityProps.at("Priority"));
1484c008028SWilliam A. Kennington III                 auto purpose =
149f442e119SVernon Mauery                     std::get<std::string>(versionProps.at("Purpose"));
150f442e119SVernon Mauery                 auto activation =
151f442e119SVernon Mauery                     std::get<std::string>(activationProps.at("Activation"));
1524c008028SWilliam A. Kennington III                 auto version =
153f442e119SVernon Mauery                     std::get<std::string>(versionProps.at("Version"));
154744398dcSNagaraju Goruganti                 if ((Version::convertVersionPurposeFromString(purpose) ==
155744398dcSNagaraju Goruganti                      Version::VersionPurpose::BMC) &&
156744398dcSNagaraju Goruganti                     (Activation::convertActivationsFromString(activation) ==
157744398dcSNagaraju Goruganti                      Activation::Activations::Active))
158744398dcSNagaraju Goruganti                 {
159744398dcSNagaraju Goruganti                     if (priority < minPriority)
160744398dcSNagaraju Goruganti                     {
161744398dcSNagaraju Goruganti                         minPriority = priority;
162744398dcSNagaraju Goruganti                         objectFound = true;
163744398dcSNagaraju Goruganti                         revision = std::move(version);
164744398dcSNagaraju Goruganti                     }
165744398dcSNagaraju Goruganti                 }
166744398dcSNagaraju Goruganti             }
167744398dcSNagaraju Goruganti             catch (const std::exception& e)
168744398dcSNagaraju Goruganti             {
16924fffdc8SGeorge Liu                 lg2::error("error message: {ERROR}", "ERROR", e);
170744398dcSNagaraju Goruganti             }
171744398dcSNagaraju Goruganti         }
172744398dcSNagaraju Goruganti     }
173744398dcSNagaraju Goruganti 
174744398dcSNagaraju Goruganti     if (!objectFound)
175744398dcSNagaraju Goruganti     {
17624fffdc8SGeorge Liu         lg2::error("Could not found an BMC software Object");
177744398dcSNagaraju Goruganti         elog<InternalFailure>();
178744398dcSNagaraju Goruganti     }
179744398dcSNagaraju Goruganti 
180744398dcSNagaraju Goruganti     return revision;
181744398dcSNagaraju Goruganti }
182744398dcSNagaraju Goruganti 
getCurrentBmcState()183ba19c184SAlexander Amelkin bool getCurrentBmcState()
184ba19c184SAlexander Amelkin {
1855d82f474SPatrick Williams     sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
186ba19c184SAlexander Amelkin 
187ba19c184SAlexander Amelkin     // Get the Inventory object implementing the BMC interface
1881318a5edSPatrick Williams     ipmi::DbusObjectInfo bmcObject =
1891318a5edSPatrick Williams         ipmi::getDbusObject(bus, bmc_state_interface);
1901318a5edSPatrick Williams     auto variant =
1911318a5edSPatrick Williams         ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first,
1921318a5edSPatrick Williams                               bmc_state_interface, bmc_state_property);
193ba19c184SAlexander Amelkin 
194f442e119SVernon Mauery     return std::holds_alternative<std::string>(variant) &&
195f442e119SVernon Mauery            BMC::convertBMCStateFromString(std::get<std::string>(variant)) ==
196f442e119SVernon Mauery                BMC::BMCState::Ready;
197ba19c184SAlexander Amelkin }
198ba19c184SAlexander Amelkin 
getCurrentBmcStateWithFallback(const bool fallbackAvailability)19994930a11SPatrick Venture bool getCurrentBmcStateWithFallback(const bool fallbackAvailability)
20094930a11SPatrick Venture {
20194930a11SPatrick Venture     try
20294930a11SPatrick Venture     {
20394930a11SPatrick Venture         return getCurrentBmcState();
20494930a11SPatrick Venture     }
20594930a11SPatrick Venture     catch (...)
20694930a11SPatrick Venture     {
20794930a11SPatrick Venture         // Nothing provided the BMC interface, therefore return whatever was
20894930a11SPatrick Venture         // configured as the default.
20994930a11SPatrick Venture         return fallbackAvailability;
21094930a11SPatrick Venture     }
21194930a11SPatrick Venture }
21294930a11SPatrick Venture 
21318d77263SYong Li namespace acpi_state
21418d77263SYong Li {
215523e2d1bSWilly Tu using namespace sdbusplus::server::xyz::openbmc_project::control::power;
21618d77263SYong Li 
21718d77263SYong Li const static constexpr char* acpiInterface =
21818d77263SYong Li     "xyz.openbmc_project.Control.Power.ACPIPowerState";
21918d77263SYong Li const static constexpr char* sysACPIProp = "SysACPIStatus";
22018d77263SYong Li const static constexpr char* devACPIProp = "DevACPIStatus";
22118d77263SYong Li 
22218d77263SYong Li enum class PowerStateType : uint8_t
22318d77263SYong Li {
22418d77263SYong Li     sysPowerState = 0x00,
22518d77263SYong Li     devPowerState = 0x01,
22618d77263SYong Li };
22718d77263SYong Li 
22818d77263SYong Li // Defined in 20.6 of ipmi doc
22918d77263SYong Li enum class PowerState : uint8_t
23018d77263SYong Li {
23118d77263SYong Li     s0G0D0 = 0x00,
23218d77263SYong Li     s1D1 = 0x01,
23318d77263SYong Li     s2D2 = 0x02,
23418d77263SYong Li     s3D3 = 0x03,
23518d77263SYong Li     s4 = 0x04,
23618d77263SYong Li     s5G2 = 0x05,
23718d77263SYong Li     s4S5 = 0x06,
23818d77263SYong Li     g3 = 0x07,
23918d77263SYong Li     sleep = 0x08,
24018d77263SYong Li     g1Sleep = 0x09,
24118d77263SYong Li     override = 0x0a,
24218d77263SYong Li     legacyOn = 0x20,
24318d77263SYong Li     legacyOff = 0x21,
24418d77263SYong Li     unknown = 0x2a,
24518d77263SYong Li     noChange = 0x7f,
24618d77263SYong Li };
24718d77263SYong Li 
24818d77263SYong Li static constexpr uint8_t stateChanged = 0x80;
24918d77263SYong Li 
25018d77263SYong Li std::map<ACPIPowerState::ACPI, PowerState> dbusToIPMI = {
25118d77263SYong Li     {ACPIPowerState::ACPI::S0_G0_D0, PowerState::s0G0D0},
25218d77263SYong Li     {ACPIPowerState::ACPI::S1_D1, PowerState::s1D1},
25318d77263SYong Li     {ACPIPowerState::ACPI::S2_D2, PowerState::s2D2},
25418d77263SYong Li     {ACPIPowerState::ACPI::S3_D3, PowerState::s3D3},
25518d77263SYong Li     {ACPIPowerState::ACPI::S4, PowerState::s4},
25618d77263SYong Li     {ACPIPowerState::ACPI::S5_G2, PowerState::s5G2},
25718d77263SYong Li     {ACPIPowerState::ACPI::S4_S5, PowerState::s4S5},
25818d77263SYong Li     {ACPIPowerState::ACPI::G3, PowerState::g3},
25918d77263SYong Li     {ACPIPowerState::ACPI::SLEEP, PowerState::sleep},
26018d77263SYong Li     {ACPIPowerState::ACPI::G1_SLEEP, PowerState::g1Sleep},
26118d77263SYong Li     {ACPIPowerState::ACPI::OVERRIDE, PowerState::override},
26218d77263SYong Li     {ACPIPowerState::ACPI::LEGACY_ON, PowerState::legacyOn},
26318d77263SYong Li     {ACPIPowerState::ACPI::LEGACY_OFF, PowerState::legacyOff},
26418d77263SYong Li     {ACPIPowerState::ACPI::Unknown, PowerState::unknown}};
26518d77263SYong Li 
isValidACPIState(acpi_state::PowerStateType type,uint8_t state)26618d77263SYong Li bool isValidACPIState(acpi_state::PowerStateType type, uint8_t state)
26718d77263SYong Li {
26818d77263SYong Li     if (type == acpi_state::PowerStateType::sysPowerState)
26918d77263SYong Li     {
27018d77263SYong Li         if ((state <= static_cast<uint8_t>(acpi_state::PowerState::override)) ||
27118d77263SYong Li             (state == static_cast<uint8_t>(acpi_state::PowerState::legacyOn)) ||
27218d77263SYong Li             (state ==
27318d77263SYong Li              static_cast<uint8_t>(acpi_state::PowerState::legacyOff)) ||
27418d77263SYong Li             (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
27518d77263SYong Li             (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
27618d77263SYong Li         {
27718d77263SYong Li             return true;
27818d77263SYong Li         }
27918d77263SYong Li         else
28018d77263SYong Li         {
28118d77263SYong Li             return false;
28218d77263SYong Li         }
28318d77263SYong Li     }
28418d77263SYong Li     else if (type == acpi_state::PowerStateType::devPowerState)
28518d77263SYong Li     {
28618d77263SYong Li         if ((state <= static_cast<uint8_t>(acpi_state::PowerState::s3D3)) ||
28718d77263SYong Li             (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
28818d77263SYong Li             (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
28918d77263SYong Li         {
29018d77263SYong Li             return true;
29118d77263SYong Li         }
29218d77263SYong Li         else
29318d77263SYong Li         {
29418d77263SYong Li             return false;
29518d77263SYong Li         }
29618d77263SYong Li     }
29718d77263SYong Li     else
29818d77263SYong Li     {
29918d77263SYong Li         return false;
30018d77263SYong Li     }
30118d77263SYong Li     return false;
30218d77263SYong Li }
30318d77263SYong Li } // namespace acpi_state
30418d77263SYong Li 
305520c1315SDeepak Kumar Sahu /** @brief implements Set ACPI Power State command
306520c1315SDeepak Kumar Sahu  * @param sysAcpiState - ACPI system power state to set
307520c1315SDeepak Kumar Sahu  * @param devAcpiState - ACPI device power state to set
308520c1315SDeepak Kumar Sahu  *
309520c1315SDeepak Kumar Sahu  * @return IPMI completion code on success
310520c1315SDeepak Kumar Sahu  **/
ipmiSetAcpiPowerState(uint8_t sysAcpiState,uint8_t devAcpiState)311520c1315SDeepak Kumar Sahu ipmi::RspType<> ipmiSetAcpiPowerState(uint8_t sysAcpiState,
312520c1315SDeepak Kumar Sahu                                       uint8_t devAcpiState)
31398a23840SMatthew Barth {
31418d77263SYong Li     auto s = static_cast<uint8_t>(acpi_state::PowerState::unknown);
31518d77263SYong Li 
3165d82f474SPatrick Williams     sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
31718d77263SYong Li 
31818d77263SYong Li     auto value = acpi_state::ACPIPowerState::ACPI::Unknown;
31918d77263SYong Li 
320520c1315SDeepak Kumar Sahu     if (sysAcpiState & acpi_state::stateChanged)
32118d77263SYong Li     {
32218d77263SYong Li         // set system power state
323520c1315SDeepak Kumar Sahu         s = sysAcpiState & ~acpi_state::stateChanged;
32418d77263SYong Li 
32518d77263SYong Li         if (!acpi_state::isValidACPIState(
32618d77263SYong Li                 acpi_state::PowerStateType::sysPowerState, s))
32718d77263SYong Li         {
32824fffdc8SGeorge Liu             lg2::error("set_acpi_power sys invalid input, S: {S}", "S", s);
329520c1315SDeepak Kumar Sahu             return ipmi::responseParmOutOfRange();
33018d77263SYong Li         }
33118d77263SYong Li 
33218d77263SYong Li         // valid input
33318d77263SYong Li         if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
33418d77263SYong Li         {
33524fffdc8SGeorge Liu             lg2::debug("No change for system power state");
33618d77263SYong Li         }
33718d77263SYong Li         else
33818d77263SYong Li         {
3391318a5edSPatrick Williams             auto found = std::find_if(
3401318a5edSPatrick Williams                 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
34118d77263SYong Li                 [&s](const auto& iter) {
34218d77263SYong Li                     return (static_cast<uint8_t>(iter.second) == s);
34318d77263SYong Li                 });
34418d77263SYong Li 
34518d77263SYong Li             value = found->first;
34618d77263SYong Li 
34718d77263SYong Li             try
34818d77263SYong Li             {
34918d77263SYong Li                 auto acpiObject =
35018d77263SYong Li                     ipmi::getDbusObject(bus, acpi_state::acpiInterface);
35118d77263SYong Li                 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
35218d77263SYong Li                                       acpi_state::acpiInterface,
35318d77263SYong Li                                       acpi_state::sysACPIProp,
35418d77263SYong Li                                       convertForMessage(value));
35518d77263SYong Li             }
35618d77263SYong Li             catch (const InternalFailure& e)
35718d77263SYong Li             {
35824fffdc8SGeorge Liu                 lg2::error("Failed in set ACPI system property: {ERROR}",
35924fffdc8SGeorge Liu                            "ERROR", e);
360520c1315SDeepak Kumar Sahu                 return ipmi::responseUnspecifiedError();
36118d77263SYong Li             }
36218d77263SYong Li         }
36318d77263SYong Li     }
36418d77263SYong Li     else
36518d77263SYong Li     {
36624fffdc8SGeorge Liu         lg2::debug("Do not change system power state");
36718d77263SYong Li     }
36818d77263SYong Li 
369520c1315SDeepak Kumar Sahu     if (devAcpiState & acpi_state::stateChanged)
37018d77263SYong Li     {
37118d77263SYong Li         // set device power state
372520c1315SDeepak Kumar Sahu         s = devAcpiState & ~acpi_state::stateChanged;
37318d77263SYong Li         if (!acpi_state::isValidACPIState(
37418d77263SYong Li                 acpi_state::PowerStateType::devPowerState, s))
37518d77263SYong Li         {
37624fffdc8SGeorge Liu             lg2::error("set_acpi_power dev invalid input, S: {S}", "S", s);
377520c1315SDeepak Kumar Sahu             return ipmi::responseParmOutOfRange();
37818d77263SYong Li         }
37918d77263SYong Li 
38018d77263SYong Li         // valid input
38118d77263SYong Li         if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
38218d77263SYong Li         {
38324fffdc8SGeorge Liu             lg2::debug("No change for device power state");
38418d77263SYong Li         }
38518d77263SYong Li         else
38618d77263SYong Li         {
3871318a5edSPatrick Williams             auto found = std::find_if(
3881318a5edSPatrick Williams                 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
38918d77263SYong Li                 [&s](const auto& iter) {
39018d77263SYong Li                     return (static_cast<uint8_t>(iter.second) == s);
39118d77263SYong Li                 });
39218d77263SYong Li 
39318d77263SYong Li             value = found->first;
39418d77263SYong Li 
39518d77263SYong Li             try
39618d77263SYong Li             {
39718d77263SYong Li                 auto acpiObject =
39818d77263SYong Li                     ipmi::getDbusObject(bus, acpi_state::acpiInterface);
39918d77263SYong Li                 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
40018d77263SYong Li                                       acpi_state::acpiInterface,
40118d77263SYong Li                                       acpi_state::devACPIProp,
40218d77263SYong Li                                       convertForMessage(value));
40318d77263SYong Li             }
40418d77263SYong Li             catch (const InternalFailure& e)
40518d77263SYong Li             {
40624fffdc8SGeorge Liu                 lg2::error("Failed in set ACPI device property: {ERROR}",
40724fffdc8SGeorge Liu                            "ERROR", e);
408520c1315SDeepak Kumar Sahu                 return ipmi::responseUnspecifiedError();
40918d77263SYong Li             }
41018d77263SYong Li         }
41118d77263SYong Li     }
41218d77263SYong Li     else
41318d77263SYong Li     {
41424fffdc8SGeorge Liu         lg2::debug("Do not change device power state");
41518d77263SYong Li     }
416520c1315SDeepak Kumar Sahu     return ipmi::responseSuccess();
41718d77263SYong Li }
41818d77263SYong Li 
4194e6d2571SDeepak Kumar Sahu /**
4204e6d2571SDeepak Kumar Sahu  *  @brief implements the get ACPI power state command
4214e6d2571SDeepak Kumar Sahu  *
4224e6d2571SDeepak Kumar Sahu  *  @return IPMI completion code plus response data on success.
4234e6d2571SDeepak Kumar Sahu  *   -  ACPI system power state
4244e6d2571SDeepak Kumar Sahu  *   -  ACPI device power state
4254e6d2571SDeepak Kumar Sahu  **/
4264e6d2571SDeepak Kumar Sahu ipmi::RspType<uint8_t, // acpiSystemPowerState
4274e6d2571SDeepak Kumar Sahu               uint8_t  // acpiDevicePowerState
4284e6d2571SDeepak Kumar Sahu               >
ipmiGetAcpiPowerState()4294e6d2571SDeepak Kumar Sahu     ipmiGetAcpiPowerState()
43018d77263SYong Li {
4314e6d2571SDeepak Kumar Sahu     uint8_t sysAcpiState;
4324e6d2571SDeepak Kumar Sahu     uint8_t devAcpiState;
43318d77263SYong Li 
4345d82f474SPatrick Williams     sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
43518d77263SYong Li 
43618d77263SYong Li     try
43718d77263SYong Li     {
43818d77263SYong Li         auto acpiObject = ipmi::getDbusObject(bus, acpi_state::acpiInterface);
43918d77263SYong Li 
44018d77263SYong Li         auto sysACPIVal = ipmi::getDbusProperty(
44118d77263SYong Li             bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
44218d77263SYong Li             acpi_state::sysACPIProp);
44318d77263SYong Li         auto sysACPI = acpi_state::ACPIPowerState::convertACPIFromString(
444f442e119SVernon Mauery             std::get<std::string>(sysACPIVal));
4454e6d2571SDeepak Kumar Sahu         sysAcpiState = static_cast<uint8_t>(acpi_state::dbusToIPMI.at(sysACPI));
44618d77263SYong Li 
44718d77263SYong Li         auto devACPIVal = ipmi::getDbusProperty(
44818d77263SYong Li             bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
44918d77263SYong Li             acpi_state::devACPIProp);
45018d77263SYong Li         auto devACPI = acpi_state::ACPIPowerState::convertACPIFromString(
451f442e119SVernon Mauery             std::get<std::string>(devACPIVal));
4524e6d2571SDeepak Kumar Sahu         devAcpiState = static_cast<uint8_t>(acpi_state::dbusToIPMI.at(devACPI));
45318d77263SYong Li     }
45418d77263SYong Li     catch (const InternalFailure& e)
45518d77263SYong Li     {
4564e6d2571SDeepak Kumar Sahu         return ipmi::responseUnspecifiedError();
45718d77263SYong Li     }
4584e6d2571SDeepak Kumar Sahu 
4594e6d2571SDeepak Kumar Sahu     return ipmi::responseSuccess(sysAcpiState, devAcpiState);
46098a23840SMatthew Barth }
46198a23840SMatthew Barth 
46298a23840SMatthew Barth typedef struct
46398a23840SMatthew Barth {
46498a23840SMatthew Barth     char major;
46598a23840SMatthew Barth     char minor;
466c7c55928SPotin Lai     uint8_t aux[4];
46786a5082fSVernon Mauery } Revision;
46898a23840SMatthew Barth 
4695d214202SPotin Lai /* Use regular expression searching matched pattern X.Y, and convert it to  */
4705d214202SPotin Lai /* Major (X) and Minor (Y) version.                                         */
4715d214202SPotin Lai /* Example:                                                                 */
4725d214202SPotin Lai /* version = 2.14.0-dev                                                     */
4735d214202SPotin Lai /*           ^ ^                                                            */
47498a23840SMatthew Barth /*           | |---------------- Minor                                      */
47598a23840SMatthew Barth /*           |------------------ Major                                      */
4765d214202SPotin Lai /*                                                                          */
477c7c55928SPotin Lai /* Default regex string only tries to match Major and Minor version.        */
478c7c55928SPotin Lai /*                                                                          */
479c7c55928SPotin Lai /* To match more firmware version info, platforms need to define it own     */
480c7c55928SPotin Lai /* regex string to match more strings, and assign correct mapping index in  */
481c7c55928SPotin Lai /* matches array.                                                           */
482c7c55928SPotin Lai /*                                                                          */
483c7c55928SPotin Lai /* matches[0]: matched index for major ver                                  */
484c7c55928SPotin Lai /* matches[1]: matched index for minor ver                                  */
485c7c55928SPotin Lai /* matches[2]: matched index for aux[0] (set 0 to skip)                     */
486c7c55928SPotin Lai /* matches[3]: matched index for aux[1] (set 0 to skip)                     */
487c7c55928SPotin Lai /* matches[4]: matched index for aux[2] (set 0 to skip)                     */
488c7c55928SPotin Lai /* matches[5]: matched index for aux[3] (set 0 to skip)                     */
489c7c55928SPotin Lai /* Example:                                                                 */
490c7c55928SPotin Lai /* regex = "([\d]+).([\d]+).([\d]+)-dev-([\d]+)-g([0-9a-fA-F]{2})           */
491c7c55928SPotin Lai /*          ([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})"               */
492c7c55928SPotin Lai /* matches = {1,2,5,6,7,8}                                                  */
493c7c55928SPotin Lai /* version = 2.14.0-dev-750-g37a7c5ad1-dirty                                */
494c7c55928SPotin Lai /*           ^ ^  ^     ^    ^ ^ ^ ^                                        */
495c7c55928SPotin Lai /*           | |  |     |    | | | |                                        */
496c7c55928SPotin Lai /*           | |  |     |    | | | |-- Aux byte 3 (0xAD), index 8           */
497c7c55928SPotin Lai /*           | |  |     |    | | |---- Aux byte 2 (0xC5), index 7           */
498c7c55928SPotin Lai /*           | |  |     |    | |------ Aux byte 1 (0xA7), index 6           */
499c7c55928SPotin Lai /*           | |  |     |    |-------- Aux byte 0 (0x37), index 5           */
500c7c55928SPotin Lai /*           | |  |     |------------- Not used, index 4                    */
501c7c55928SPotin Lai /*           | |  |------------------- Not used, index 3                    */
502c7c55928SPotin Lai /*           | |---------------------- Minor (14), index 2                  */
503c7c55928SPotin Lai /*           |------------------------ Major (2), index 1                   */
convertVersion(std::string s,Revision & rev)5045d214202SPotin Lai int convertVersion(std::string s, Revision& rev)
50598a23840SMatthew Barth {
506c7c55928SPotin Lai     static const std::vector<size_t> matches = {
507c7c55928SPotin Lai         MAJOR_MATCH_INDEX, MINOR_MATCH_INDEX, AUX_0_MATCH_INDEX,
508c7c55928SPotin Lai         AUX_1_MATCH_INDEX, AUX_2_MATCH_INDEX, AUX_3_MATCH_INDEX};
5095d214202SPotin Lai     std::regex fw_regex(FW_VER_REGEX);
5105d214202SPotin Lai     std::smatch m;
5115d214202SPotin Lai     Revision r = {0};
5125d214202SPotin Lai     size_t val;
51398a23840SMatthew Barth 
514dcde04e0SPotin Lai     if (std::regex_search(s, m, fw_regex))
5152b7e07d3SDinesh Chinari     {
516c7c55928SPotin Lai         if (m.size() < *std::max_element(matches.begin(), matches.end()))
517c7c55928SPotin Lai         { // max index higher than match count
518dcde04e0SPotin Lai             return -1;
519dcde04e0SPotin Lai         }
520dcde04e0SPotin Lai 
5215d214202SPotin Lai         // convert major
5225d214202SPotin Lai         {
523*a6c307a8SJayanth Othayoth             std::string str = m[matches[0]].str();
524*a6c307a8SJayanth Othayoth             const auto& [ptr, ec] =
525*a6c307a8SJayanth Othayoth                 std::from_chars(str.data(), str.data() + str.size(), val);
526*a6c307a8SJayanth Othayoth             if (ec != std::errc() || ptr != str.data() + str.size())
5275d214202SPotin Lai             { // failed to convert major string
528dcde04e0SPotin Lai                 return -1;
5295d214202SPotin Lai             }
530058e291fSPotin Lai 
531058e291fSPotin Lai             if (val >= 2000)
532058e291fSPotin Lai             { // For the platforms use year as major version, it would expect to
533058e291fSPotin Lai               // have major version between 0 - 99. If the major version is
534058e291fSPotin Lai               // greater than or equal to 2000, it is treated as a year and
535058e291fSPotin Lai               // converted to 0 - 99.
536058e291fSPotin Lai                 r.major = val % 100;
537058e291fSPotin Lai             }
538058e291fSPotin Lai             else
539058e291fSPotin Lai             {
5405d214202SPotin Lai                 r.major = val & 0x7F;
5412b7e07d3SDinesh Chinari             }
542058e291fSPotin Lai         }
54398a23840SMatthew Barth 
5445d214202SPotin Lai         // convert minor
5452b7e07d3SDinesh Chinari         {
546*a6c307a8SJayanth Othayoth             std::string str = m[matches[1]].str();
547*a6c307a8SJayanth Othayoth             const auto& [ptr, ec] =
548*a6c307a8SJayanth Othayoth                 std::from_chars(str.data(), str.data() + str.size(), val);
549*a6c307a8SJayanth Othayoth             if (ec != std::errc() || ptr != str.data() + str.size())
5505d214202SPotin Lai             { // failed to convert minor string
551dcde04e0SPotin Lai                 return -1;
552886d6840SWilly Tu             }
5535d214202SPotin Lai             r.minor = val & 0xFF;
5542b7e07d3SDinesh Chinari         }
55598a23840SMatthew Barth 
556c7c55928SPotin Lai         // convert aux bytes
557c7c55928SPotin Lai         {
558c7c55928SPotin Lai             size_t i;
559c7c55928SPotin Lai             for (i = 0; i < 4; i++)
560c7c55928SPotin Lai             {
561c7c55928SPotin Lai                 if (matches[i + 2] == 0)
562c7c55928SPotin Lai                 {
563c7c55928SPotin Lai                     continue;
564c7c55928SPotin Lai                 }
565c7c55928SPotin Lai 
566*a6c307a8SJayanth Othayoth                 std::string str = m[matches[i + 2]].str();
567*a6c307a8SJayanth Othayoth                 const char* cstr = str.c_str();
568c7c55928SPotin Lai                 auto [ptr,
569*a6c307a8SJayanth Othayoth                       ec] = std::from_chars(cstr, cstr + str.size(), val, 16);
570*a6c307a8SJayanth Othayoth                 if (ec != std::errc() || ptr != cstr + str.size())
571c7c55928SPotin Lai                 { // failed to convert aux byte string
572c7c55928SPotin Lai                     break;
573c7c55928SPotin Lai                 }
574c7c55928SPotin Lai 
575c7c55928SPotin Lai                 r.aux[i] = val & 0xFF;
576c7c55928SPotin Lai             }
577c7c55928SPotin Lai 
578c7c55928SPotin Lai             if (i != 4)
579c7c55928SPotin Lai             { // something wrong durign converting aux bytes
580c7c55928SPotin Lai                 return -1;
581c7c55928SPotin Lai             }
582c7c55928SPotin Lai         }
583c7c55928SPotin Lai 
5845d214202SPotin Lai         // all matched
5855d214202SPotin Lai         rev = r;
58698a23840SMatthew Barth         return 0;
58798a23840SMatthew Barth     }
58898a23840SMatthew Barth 
5895d214202SPotin Lai     return -1;
5905d214202SPotin Lai }
5915d214202SPotin Lai 
592ea1c401cSVernon Mauery /* @brief: Implement the Get Device ID IPMI command per the IPMI spec
593ea1c401cSVernon Mauery  *  @param[in] ctx - shared_ptr to an IPMI context struct
594ea1c401cSVernon Mauery  *
595ea1c401cSVernon Mauery  *  @returns IPMI completion code plus response data
596ea1c401cSVernon Mauery  *   - Device ID (manufacturer defined)
597ea1c401cSVernon Mauery  *   - Device revision[4 bits]; reserved[3 bits]; SDR support[1 bit]
598ea1c401cSVernon Mauery  *   - FW revision major[7 bits] (binary encoded); available[1 bit]
599ea1c401cSVernon Mauery  *   - FW Revision minor (BCD encoded)
600ea1c401cSVernon Mauery  *   - IPMI version (0x02 for IPMI 2.0)
601ea1c401cSVernon Mauery  *   - device support (bitfield of supported options)
602ea1c401cSVernon Mauery  *   - MFG IANA ID (3 bytes)
603ea1c401cSVernon Mauery  *   - product ID (2 bytes)
604ea1c401cSVernon Mauery  *   - AUX info (4 bytes)
605ea1c401cSVernon Mauery  */
606ea1c401cSVernon Mauery ipmi::RspType<uint8_t,  // Device ID
60786a5082fSVernon Mauery               uint8_t,  // Device Revision
60886a5082fSVernon Mauery               uint8_t,  // Firmware Revision Major
60986a5082fSVernon Mauery               uint8_t,  // Firmware Revision minor
61086a5082fSVernon Mauery               uint8_t,  // IPMI version
61186a5082fSVernon Mauery               uint8_t,  // Additional device support
61286a5082fSVernon Mauery               uint24_t, // MFG ID
61386a5082fSVernon Mauery               uint16_t, // Product ID
61486a5082fSVernon Mauery               uint32_t  // AUX info
61586a5082fSVernon Mauery               >
ipmiAppGetDeviceId(ipmi::Context::ptr ctx)61611d68897SWilly Tu     ipmiAppGetDeviceId([[maybe_unused]] ipmi::Context::ptr ctx)
61798a23840SMatthew Barth {
61886a5082fSVernon Mauery     static struct
61986a5082fSVernon Mauery     {
62086a5082fSVernon Mauery         uint8_t id;
62186a5082fSVernon Mauery         uint8_t revision;
62286a5082fSVernon Mauery         uint8_t fw[2];
62386a5082fSVernon Mauery         uint8_t ipmiVer;
62486a5082fSVernon Mauery         uint8_t addnDevSupport;
62586a5082fSVernon Mauery         uint24_t manufId;
62686a5082fSVernon Mauery         uint16_t prodId;
62786a5082fSVernon Mauery         uint32_t aux;
62886a5082fSVernon Mauery     } devId;
629a1adb077SDavid Cobbley     static bool dev_id_initialized = false;
63094930a11SPatrick Venture     static bool defaultActivationSetting = true;
631a1adb077SDavid Cobbley     const char* filename = "/usr/share/ipmi-providers/dev_id.json";
632ba19c184SAlexander Amelkin     constexpr auto ipmiDevIdStateShift = 7;
633ba19c184SAlexander Amelkin     constexpr auto ipmiDevIdFw1Mask = ~(1 << ipmiDevIdStateShift);
634b78184e7SWilly Tu 
635b78184e7SWilly Tu #ifdef GET_DBUS_ACTIVE_SOFTWARE
636b78184e7SWilly Tu     static bool haveBMCVersion = false;
63727a62ecaSJeffLin     if (!haveBMCVersion || !dev_id_initialized)
638a1adb077SDavid Cobbley     {
639b78184e7SWilly Tu         int r = -1;
640ceee811eSJayanth Othayoth         Revision rev = {0, 0, {0, 0, 0, 0}};
641744398dcSNagaraju Goruganti         try
642744398dcSNagaraju Goruganti         {
643ea1c401cSVernon Mauery             auto version = getActiveSoftwareVersionInfo(ctx);
64486a5082fSVernon Mauery             r = convertVersion(version, rev);
645eb9b8144SSergey Solomin         }
646744398dcSNagaraju Goruganti         catch (const std::exception& e)
647744398dcSNagaraju Goruganti         {
64824fffdc8SGeorge Liu             lg2::error("error message: {ERROR}", "ERROR", e);
649744398dcSNagaraju Goruganti         }
650744398dcSNagaraju Goruganti 
6510b02be92SPatrick Venture         if (r >= 0)
6520b02be92SPatrick Venture         {
653a1adb077SDavid Cobbley             // bit7 identifies if the device is available
654a1adb077SDavid Cobbley             // 0=normal operation
655a1adb077SDavid Cobbley             // 1=device firmware, SDR update,
656a1adb077SDavid Cobbley             // or self-initialization in progress.
657ba19c184SAlexander Amelkin             // The availability may change in run time, so mask here
658ba19c184SAlexander Amelkin             // and initialize later.
65986a5082fSVernon Mauery             devId.fw[0] = rev.major & ipmiDevIdFw1Mask;
66098a23840SMatthew Barth 
66198a23840SMatthew Barth             rev.minor = (rev.minor > 99 ? 99 : rev.minor);
66286a5082fSVernon Mauery             devId.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16;
663c7c55928SPotin Lai             std::memcpy(&devId.aux, rev.aux, sizeof(rev.aux));
664c1f5aca0SBrandon Kim             haveBMCVersion = true;
66598a23840SMatthew Barth         }
66627a62ecaSJeffLin     }
667b78184e7SWilly Tu #endif
66827a62ecaSJeffLin     if (!dev_id_initialized)
66927a62ecaSJeffLin     {
6708991dd62SGunnar Mills         // IPMI Spec version 2.0
67186a5082fSVernon Mauery         devId.ipmiVer = 2;
672ee0cb902SNan Li 
67386a5082fSVernon Mauery         std::ifstream devIdFile(filename);
67486a5082fSVernon Mauery         if (devIdFile.is_open())
675a1adb077SDavid Cobbley         {
67686a5082fSVernon Mauery             auto data = nlohmann::json::parse(devIdFile, nullptr, false);
677a1adb077SDavid Cobbley             if (!data.is_discarded())
678a1adb077SDavid Cobbley             {
67986a5082fSVernon Mauery                 devId.id = data.value("id", 0);
68086a5082fSVernon Mauery                 devId.revision = data.value("revision", 0);
68186a5082fSVernon Mauery                 devId.addnDevSupport = data.value("addn_dev_support", 0);
68286a5082fSVernon Mauery                 devId.manufId = data.value("manuf_id", 0);
68386a5082fSVernon Mauery                 devId.prodId = data.value("prod_id", 0);
6849a686366SPotin Lai #ifdef GET_DBUS_ACTIVE_SOFTWARE
6859a686366SPotin Lai                 if (!(AUX_0_MATCH_INDEX || AUX_1_MATCH_INDEX ||
6869a686366SPotin Lai                       AUX_2_MATCH_INDEX || AUX_3_MATCH_INDEX))
6879a686366SPotin Lai #endif
6889a686366SPotin Lai                 {
68986a5082fSVernon Mauery                     devId.aux = data.value("aux", 0);
6909a686366SPotin Lai                 }
691ee0cb902SNan Li 
692bfd3a17fSWilly Tu                 if (data.contains("firmware_revision"))
693bfd3a17fSWilly Tu                 {
694bfd3a17fSWilly Tu                     const auto& firmwareRevision = data.at("firmware_revision");
695bfd3a17fSWilly Tu                     if (firmwareRevision.contains("major"))
696bfd3a17fSWilly Tu                     {
697bfd3a17fSWilly Tu                         firmwareRevision.at("major").get_to(devId.fw[0]);
698bfd3a17fSWilly Tu                     }
699bfd3a17fSWilly Tu                     if (firmwareRevision.contains("minor"))
700bfd3a17fSWilly Tu                     {
701bfd3a17fSWilly Tu                         firmwareRevision.at("minor").get_to(devId.fw[1]);
702bfd3a17fSWilly Tu                     }
703bfd3a17fSWilly Tu                 }
704bfd3a17fSWilly Tu 
70594930a11SPatrick Venture                 // Set the availablitity of the BMC.
70694930a11SPatrick Venture                 defaultActivationSetting = data.value("availability", true);
70794930a11SPatrick Venture 
708a1adb077SDavid Cobbley                 // Don't read the file every time if successful
709a1adb077SDavid Cobbley                 dev_id_initialized = true;
710a1adb077SDavid Cobbley             }
711a1adb077SDavid Cobbley             else
712a1adb077SDavid Cobbley             {
71324fffdc8SGeorge Liu                 lg2::error("Device ID JSON parser failure");
714f2587fceSVernon Mauery                 return ipmi::responseUnspecifiedError();
715a1adb077SDavid Cobbley             }
716a1adb077SDavid Cobbley         }
717a1adb077SDavid Cobbley         else
718a1adb077SDavid Cobbley         {
71924fffdc8SGeorge Liu             lg2::error("Device ID file not found");
720f2587fceSVernon Mauery             return ipmi::responseUnspecifiedError();
721a1adb077SDavid Cobbley         }
722a1adb077SDavid Cobbley     }
723ee0cb902SNan Li 
724ba19c184SAlexander Amelkin     // Set availability to the actual current BMC state
72586a5082fSVernon Mauery     devId.fw[0] &= ipmiDevIdFw1Mask;
72694930a11SPatrick Venture     if (!getCurrentBmcStateWithFallback(defaultActivationSetting))
727ba19c184SAlexander Amelkin     {
72886a5082fSVernon Mauery         devId.fw[0] |= (1 << ipmiDevIdStateShift);
729ba19c184SAlexander Amelkin     }
730ba19c184SAlexander Amelkin 
73186a5082fSVernon Mauery     return ipmi::responseSuccess(
73286a5082fSVernon Mauery         devId.id, devId.revision, devId.fw[0], devId.fw[1], devId.ipmiVer,
73386a5082fSVernon Mauery         devId.addnDevSupport, devId.manufId, devId.prodId, devId.aux);
73498a23840SMatthew Barth }
73598a23840SMatthew Barth 
ipmiAppGetSelfTestResults()736b84a5282SVernon Mauery auto ipmiAppGetSelfTestResults() -> ipmi::RspType<uint8_t, uint8_t>
73741fa24a1SNan Li {
73841fa24a1SNan Li     // Byte 2:
73941fa24a1SNan Li     //  55h - No error.
7408991dd62SGunnar Mills     //  56h - Self Test function not implemented in this controller.
74141fa24a1SNan Li     //  57h - Corrupted or inaccesssible data or devices.
74241fa24a1SNan Li     //  58h - Fatal hardware error.
74341fa24a1SNan Li     //  FFh - reserved.
74441fa24a1SNan Li     //  all other: Device-specific 'internal failure'.
74541fa24a1SNan Li     //  Byte 3:
74641fa24a1SNan Li     //      For byte 2 = 55h, 56h, FFh:     00h
74741fa24a1SNan Li     //      For byte 2 = 58h, all other:    Device-specific
74841fa24a1SNan Li     //      For byte 2 = 57h:   self-test error bitfield.
74941fa24a1SNan Li     //      Note: returning 57h does not imply that all test were run.
75041fa24a1SNan Li     //      [7] 1b = Cannot access SEL device.
75141fa24a1SNan Li     //      [6] 1b = Cannot access SDR Repository.
75241fa24a1SNan Li     //      [5] 1b = Cannot access BMC FRU device.
75341fa24a1SNan Li     //      [4] 1b = IPMB signal lines do not respond.
75441fa24a1SNan Li     //      [3] 1b = SDR Repository empty.
75541fa24a1SNan Li     //      [2] 1b = Internal Use Area of BMC FRU corrupted.
75641fa24a1SNan Li     //      [1] 1b = controller update 'boot block' firmware corrupted.
75741fa24a1SNan Li     //      [0] 1b = controller operational firmware corrupted.
758b84a5282SVernon Mauery     constexpr uint8_t notImplemented = 0x56;
759b84a5282SVernon Mauery     constexpr uint8_t zero = 0;
760b84a5282SVernon Mauery     return ipmi::responseSuccess(notImplemented, zero);
76141fa24a1SNan Li }
76241fa24a1SNan Li 
7631554132bSVernon Mauery static constexpr size_t uuidBinaryLength = 16;
rfc4122ToIpmi(std::string rfc4122)7641554132bSVernon Mauery static std::array<uint8_t, uuidBinaryLength> rfc4122ToIpmi(std::string rfc4122)
76598a23840SMatthew Barth {
766523e2d1bSWilly Tu     using Argument = xyz::openbmc_project::common::InvalidArgument;
76798a23840SMatthew Barth     // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
768d211702bSPatrick Venture     // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte
769d211702bSPatrick Venture     // order
77098a23840SMatthew Barth     // Ex: 0x2332fc2c40e66298e511f2782395a361
7711554132bSVernon Mauery     constexpr size_t uuidHexLength = (2 * uuidBinaryLength);
7721554132bSVernon Mauery     constexpr size_t uuidRfc4122Length = (uuidHexLength + 4);
7731554132bSVernon Mauery     std::array<uint8_t, uuidBinaryLength> uuid;
7741554132bSVernon Mauery     if (rfc4122.size() == uuidRfc4122Length)
7750b02be92SPatrick Venture     {
7761554132bSVernon Mauery         rfc4122.erase(std::remove(rfc4122.begin(), rfc4122.end(), '-'),
7771554132bSVernon Mauery                       rfc4122.end());
778eb9b8144SSergey Solomin     }
7791554132bSVernon Mauery     if (rfc4122.size() != uuidHexLength)
78098a23840SMatthew Barth     {
7811554132bSVernon Mauery         elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"),
7821554132bSVernon Mauery                               Argument::ARGUMENT_VALUE(rfc4122.c_str()));
7831554132bSVernon Mauery     }
7841554132bSVernon Mauery     for (size_t ind = 0; ind < uuidHexLength; ind += 2)
7851554132bSVernon Mauery     {
7861554132bSVernon Mauery         char v[3];
7871554132bSVernon Mauery         v[0] = rfc4122[ind];
7881554132bSVernon Mauery         v[1] = rfc4122[ind + 1];
7891554132bSVernon Mauery         v[2] = 0;
7901554132bSVernon Mauery         size_t err;
7911554132bSVernon Mauery         long b;
7921554132bSVernon Mauery         try
7931554132bSVernon Mauery         {
7941554132bSVernon Mauery             b = std::stoul(v, &err, 16);
7951554132bSVernon Mauery         }
796a2ad2da8SPatrick Williams         catch (const std::exception& e)
7971554132bSVernon Mauery         {
7981554132bSVernon Mauery             elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"),
7991554132bSVernon Mauery                                   Argument::ARGUMENT_VALUE(rfc4122.c_str()));
8001554132bSVernon Mauery         }
8011554132bSVernon Mauery         // check that exactly two ascii bytes were converted
8021554132bSVernon Mauery         if (err != 2)
8031554132bSVernon Mauery         {
8041554132bSVernon Mauery             elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"),
8051554132bSVernon Mauery                                   Argument::ARGUMENT_VALUE(rfc4122.c_str()));
8061554132bSVernon Mauery         }
8071554132bSVernon Mauery         uuid[uuidBinaryLength - (ind / 2) - 1] = static_cast<uint8_t>(b);
8081554132bSVernon Mauery     }
8091554132bSVernon Mauery     return uuid;
81098a23840SMatthew Barth }
81198a23840SMatthew Barth 
ipmiAppGetDeviceGuid()8121554132bSVernon Mauery auto ipmiAppGetDeviceGuid()
8131554132bSVernon Mauery     -> ipmi::RspType<std::array<uint8_t, uuidBinaryLength>>
81498a23840SMatthew Barth {
8151554132bSVernon Mauery     // return a fixed GUID based on /etc/machine-id
8161554132bSVernon Mauery     // This should match the /redfish/v1/Managers/bmc's UUID data
81798a23840SMatthew Barth 
8181554132bSVernon Mauery     // machine specific application ID (for BMC ID)
8191554132bSVernon Mauery     // generated by systemd-id128 -p new as per man page
8201554132bSVernon Mauery     static constexpr sd_id128_t bmcUuidAppId = SD_ID128_MAKE(
8211554132bSVernon Mauery         e0, e1, 73, 76, 64, 61, 47, da, a5, 0c, d0, cc, 64, 12, 45, 78);
82298a23840SMatthew Barth 
8231554132bSVernon Mauery     sd_id128_t bmcUuid;
8241554132bSVernon Mauery     // create the UUID from /etc/machine-id via the systemd API
8251554132bSVernon Mauery     sd_id128_get_machine_app_specific(bmcUuidAppId, &bmcUuid);
82698a23840SMatthew Barth 
8271554132bSVernon Mauery     char bmcUuidCstr[SD_ID128_STRING_MAX];
8281554132bSVernon Mauery     std::string systemUuid = sd_id128_to_string(bmcUuid, bmcUuidCstr);
82998a23840SMatthew Barth 
8301554132bSVernon Mauery     std::array<uint8_t, uuidBinaryLength> uuid = rfc4122ToIpmi(systemUuid);
8311554132bSVernon Mauery     return ipmi::responseSuccess(uuid);
83298a23840SMatthew Barth }
83398a23840SMatthew Barth 
ipmiAppGetBtCapabilities()834cc99ba43SVernon Mauery auto ipmiAppGetBtCapabilities()
835cc99ba43SVernon Mauery     -> ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t>
83698a23840SMatthew Barth {
83788ad815dSAdriana Kobylak     // Per IPMI 2.0 spec, the input and output buffer size must be the max
83888ad815dSAdriana Kobylak     // buffer size minus one byte to allocate space for the length byte.
839cc99ba43SVernon Mauery     constexpr uint8_t nrOutstanding = 0x01;
840cc99ba43SVernon Mauery     constexpr uint8_t inputBufferSize = MAX_IPMI_BUFFER - 1;
841cc99ba43SVernon Mauery     constexpr uint8_t outputBufferSize = MAX_IPMI_BUFFER - 1;
842cc99ba43SVernon Mauery     constexpr uint8_t transactionTime = 0x0A;
843cc99ba43SVernon Mauery     constexpr uint8_t nrRetries = 0x01;
84498a23840SMatthew Barth 
845cc99ba43SVernon Mauery     return ipmi::responseSuccess(nrOutstanding, inputBufferSize,
846cc99ba43SVernon Mauery                                  outputBufferSize, transactionTime, nrRetries);
84798a23840SMatthew Barth }
84898a23840SMatthew Barth 
ipmiAppGetSystemGuid(ipmi::Context::ptr & ctx)8496c44a94dSVernon Mauery auto ipmiAppGetSystemGuid(ipmi::Context::ptr& ctx)
8506c44a94dSVernon Mauery     -> ipmi::RspType<std::array<uint8_t, 16>>
8515e007a5dSMarri Devender Rao {
852b90a5328SVernon Mauery     static constexpr auto uuidInterface = "xyz.openbmc_project.Common.UUID";
853b90a5328SVernon Mauery     static constexpr auto uuidProperty = "UUID";
8545e007a5dSMarri Devender Rao 
8555e007a5dSMarri Devender Rao     // Get the Inventory object implementing BMC interface
8566c44a94dSVernon Mauery     ipmi::DbusObjectInfo objectInfo{};
857d386fba6SHieu Huynh     boost::system::error_code ec = ipmi::getDbusObject(
858d386fba6SHieu Huynh         ctx, uuidInterface, ipmi::sensor::inventoryRoot, objectInfo);
8596c44a94dSVernon Mauery     if (ec.value())
8606c44a94dSVernon Mauery     {
86124fffdc8SGeorge Liu         lg2::error("Failed to locate System UUID object, "
86224fffdc8SGeorge Liu                    "interface: {INTERFACE}, error: {ERROR}",
86324fffdc8SGeorge Liu                    "INTERFACE", uuidInterface, "ERROR", ec.message());
8646c44a94dSVernon Mauery     }
8655e007a5dSMarri Devender Rao 
8665e007a5dSMarri Devender Rao     // Read UUID property value from bmcObject
8675e007a5dSMarri Devender Rao     // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
8686c44a94dSVernon Mauery     std::string rfc4122Uuid{};
8696c44a94dSVernon Mauery     ec = ipmi::getDbusProperty(ctx, objectInfo.second, objectInfo.first,
8706c44a94dSVernon Mauery                                uuidInterface, uuidProperty, rfc4122Uuid);
8716c44a94dSVernon Mauery     if (ec.value())
8725e007a5dSMarri Devender Rao     {
87324fffdc8SGeorge Liu         lg2::error("Failed to read System UUID property, "
87424fffdc8SGeorge Liu                    "interface: {INTERFACE}, property: {PROPERTY}, "
87524fffdc8SGeorge Liu                    "error: {ERROR}",
87624fffdc8SGeorge Liu                    "INTERFACE", uuidInterface, "PROPERTY", uuidProperty,
87724fffdc8SGeorge Liu                    "ERROR", ec.message());
878b90a5328SVernon Mauery         return ipmi::responseUnspecifiedError();
8795e007a5dSMarri Devender Rao     }
880b90a5328SVernon Mauery     std::array<uint8_t, 16> uuid;
881b90a5328SVernon Mauery     try
882b90a5328SVernon Mauery     {
883b90a5328SVernon Mauery         // convert to IPMI format
884b90a5328SVernon Mauery         uuid = rfc4122ToIpmi(rfc4122Uuid);
885b90a5328SVernon Mauery     }
886b90a5328SVernon Mauery     catch (const InvalidArgument& e)
887b90a5328SVernon Mauery     {
88824fffdc8SGeorge Liu         lg2::error("Failed in parsing BMC UUID property, "
88924fffdc8SGeorge Liu                    "interface: {INTERFACE}, property: {PROPERTY}, "
89024fffdc8SGeorge Liu                    "value: {VALUE}, error: {ERROR}",
89124fffdc8SGeorge Liu                    "INTERFACE", uuidInterface, "PROPERTY", uuidProperty,
89224fffdc8SGeorge Liu                    "VALUE", rfc4122Uuid, "ERROR", e);
893b90a5328SVernon Mauery         return ipmi::responseUnspecifiedError();
894b90a5328SVernon Mauery     }
895b90a5328SVernon Mauery     return ipmi::responseSuccess(uuid);
8965e007a5dSMarri Devender Rao }
8975e007a5dSMarri Devender Rao 
898e7023926SRajashekar Gade Reddy /**
899e7023926SRajashekar Gade Reddy  * @brief set the session state as teardown
900e7023926SRajashekar Gade Reddy  *
901e7023926SRajashekar Gade Reddy  * This function is to set the session state to tear down in progress if the
902e7023926SRajashekar Gade Reddy  * state is active.
903e7023926SRajashekar Gade Reddy  *
904e7023926SRajashekar Gade Reddy  * @param[in] busp - Dbus obj
905e7023926SRajashekar Gade Reddy  * @param[in] service - service name
906e7023926SRajashekar Gade Reddy  * @param[in] obj - object path
907e7023926SRajashekar Gade Reddy  *
908e7023926SRajashekar Gade Reddy  * @return success completion code if it sets the session state to
909e7023926SRajashekar Gade Reddy  * tearDownInProgress else return the corresponding error completion code.
910e7023926SRajashekar Gade Reddy  **/
setSessionState(std::shared_ptr<sdbusplus::asio::connection> & busp,const std::string & service,const std::string & obj)911e7023926SRajashekar Gade Reddy uint8_t setSessionState(std::shared_ptr<sdbusplus::asio::connection>& busp,
912e7023926SRajashekar Gade Reddy                         const std::string& service, const std::string& obj)
913e7023926SRajashekar Gade Reddy {
914e7023926SRajashekar Gade Reddy     try
915e7023926SRajashekar Gade Reddy     {
916e7023926SRajashekar Gade Reddy         uint8_t sessionState = std::get<uint8_t>(ipmi::getDbusProperty(
917e7023926SRajashekar Gade Reddy             *busp, service, obj, session::sessionIntf, "State"));
918e7023926SRajashekar Gade Reddy 
919e7023926SRajashekar Gade Reddy         if (sessionState == static_cast<uint8_t>(session::State::active))
920e7023926SRajashekar Gade Reddy         {
921e7023926SRajashekar Gade Reddy             ipmi::setDbusProperty(
922e7023926SRajashekar Gade Reddy                 *busp, service, obj, session::sessionIntf, "State",
923e7023926SRajashekar Gade Reddy                 static_cast<uint8_t>(session::State::tearDownInProgress));
924e7023926SRajashekar Gade Reddy             return ipmi::ccSuccess;
925e7023926SRajashekar Gade Reddy         }
926e7023926SRajashekar Gade Reddy     }
927a2ad2da8SPatrick Williams     catch (const std::exception& e)
928e7023926SRajashekar Gade Reddy     {
92924fffdc8SGeorge Liu         lg2::error("Failed in getting session state property, "
93024fffdc8SGeorge Liu                    "service: {SERVICE}, object path: {OBJECT_PATH}, "
93124fffdc8SGeorge Liu                    "interface: {INTERFACE}, error: {ERROR}",
93224fffdc8SGeorge Liu                    "SERVICE", service, "OBJECT_PATH", obj, "INTERFACE",
93324fffdc8SGeorge Liu                    session::sessionIntf, "ERROR", e);
934e7023926SRajashekar Gade Reddy         return ipmi::ccUnspecifiedError;
935e7023926SRajashekar Gade Reddy     }
936e7023926SRajashekar Gade Reddy 
937e7023926SRajashekar Gade Reddy     return ipmi::ccInvalidFieldRequest;
938e7023926SRajashekar Gade Reddy }
939e7023926SRajashekar Gade Reddy 
ipmiAppCloseSession(uint32_t reqSessionId,std::optional<uint8_t> requestSessionHandle)940e7023926SRajashekar Gade Reddy ipmi::RspType<> ipmiAppCloseSession(uint32_t reqSessionId,
941e7023926SRajashekar Gade Reddy                                     std::optional<uint8_t> requestSessionHandle)
942e7023926SRajashekar Gade Reddy {
943e7023926SRajashekar Gade Reddy     auto busp = getSdBus();
944e7023926SRajashekar Gade Reddy     uint8_t reqSessionHandle =
945e7023926SRajashekar Gade Reddy         requestSessionHandle.value_or(session::defaultSessionHandle);
946e7023926SRajashekar Gade Reddy 
947e7023926SRajashekar Gade Reddy     if (reqSessionId == session::sessionZero &&
948e7023926SRajashekar Gade Reddy         reqSessionHandle == session::defaultSessionHandle)
949e7023926SRajashekar Gade Reddy     {
950e7023926SRajashekar Gade Reddy         return ipmi::response(session::ccInvalidSessionId);
951e7023926SRajashekar Gade Reddy     }
952e7023926SRajashekar Gade Reddy 
953e7023926SRajashekar Gade Reddy     if (reqSessionId == session::sessionZero &&
954e7023926SRajashekar Gade Reddy         reqSessionHandle == session::invalidSessionHandle)
955e7023926SRajashekar Gade Reddy     {
956e7023926SRajashekar Gade Reddy         return ipmi::response(session::ccInvalidSessionHandle);
957e7023926SRajashekar Gade Reddy     }
958e7023926SRajashekar Gade Reddy 
959e7023926SRajashekar Gade Reddy     if (reqSessionId != session::sessionZero &&
960e7023926SRajashekar Gade Reddy         reqSessionHandle != session::defaultSessionHandle)
961e7023926SRajashekar Gade Reddy     {
962e7023926SRajashekar Gade Reddy         return ipmi::response(ipmi::ccInvalidFieldRequest);
963e7023926SRajashekar Gade Reddy     }
964e7023926SRajashekar Gade Reddy 
965e7023926SRajashekar Gade Reddy     try
966e7023926SRajashekar Gade Reddy     {
967e7023926SRajashekar Gade Reddy         ipmi::ObjectTree objectTree = ipmi::getAllDbusObjects(
968e7023926SRajashekar Gade Reddy             *busp, session::sessionManagerRootPath, session::sessionIntf);
969e7023926SRajashekar Gade Reddy 
970e7023926SRajashekar Gade Reddy         for (auto& objectTreeItr : objectTree)
971e7023926SRajashekar Gade Reddy         {
972e7023926SRajashekar Gade Reddy             const std::string obj = objectTreeItr.first;
973e7023926SRajashekar Gade Reddy 
974e7023926SRajashekar Gade Reddy             if (isSessionObjectMatched(obj, reqSessionId, reqSessionHandle))
975e7023926SRajashekar Gade Reddy             {
976e7023926SRajashekar Gade Reddy                 auto& serviceMap = objectTreeItr.second;
977e7023926SRajashekar Gade Reddy 
978e7023926SRajashekar Gade Reddy                 // Session id and session handle are unique for each session.
979e7023926SRajashekar Gade Reddy                 // Session id and handler are retrived from the object path and
980e7023926SRajashekar Gade Reddy                 // object path will be unique for each session. Checking if
981e7023926SRajashekar Gade Reddy                 // multiple objects exist with same object path under multiple
982e7023926SRajashekar Gade Reddy                 // services.
983e7023926SRajashekar Gade Reddy                 if (serviceMap.size() != 1)
984e7023926SRajashekar Gade Reddy                 {
985e7023926SRajashekar Gade Reddy                     return ipmi::responseUnspecifiedError();
986e7023926SRajashekar Gade Reddy                 }
987e7023926SRajashekar Gade Reddy 
988e7023926SRajashekar Gade Reddy                 auto itr = serviceMap.begin();
989e7023926SRajashekar Gade Reddy                 const std::string service = itr->first;
990e7023926SRajashekar Gade Reddy                 return ipmi::response(setSessionState(busp, service, obj));
991e7023926SRajashekar Gade Reddy             }
992e7023926SRajashekar Gade Reddy         }
993e7023926SRajashekar Gade Reddy     }
9945d82f474SPatrick Williams     catch (const sdbusplus::exception_t& e)
995e7023926SRajashekar Gade Reddy     {
99624fffdc8SGeorge Liu         lg2::error("Failed to fetch object from dbus, "
99724fffdc8SGeorge Liu                    "interface: {INTERFACE}, error: {ERROR}",
99824fffdc8SGeorge Liu                    "INTERFACE", session::sessionIntf, "ERROR", e);
999e7023926SRajashekar Gade Reddy         return ipmi::responseUnspecifiedError();
1000e7023926SRajashekar Gade Reddy     }
1001e7023926SRajashekar Gade Reddy 
1002e7023926SRajashekar Gade Reddy     return ipmi::responseInvalidFieldRequest();
1003e7023926SRajashekar Gade Reddy }
1004e7023926SRajashekar Gade Reddy 
getTotalSessionCount()1005f71444daSRajashekar Gade Reddy uint8_t getTotalSessionCount()
1006f71444daSRajashekar Gade Reddy {
1007c178948eSMeera-Katta     uint8_t count = 0, ch = 0;
1008f71444daSRajashekar Gade Reddy 
1009f71444daSRajashekar Gade Reddy     while (ch < ipmi::maxIpmiChannels &&
1010f71444daSRajashekar Gade Reddy            count < session::maxNetworkInstanceSupported)
1011f71444daSRajashekar Gade Reddy     {
101280207e62SJayaprakash Mutyala         ipmi::ChannelInfo chInfo{};
1013f71444daSRajashekar Gade Reddy         ipmi::getChannelInfo(ch, chInfo);
1014f71444daSRajashekar Gade Reddy         if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
1015f71444daSRajashekar Gade Reddy             ipmi::EChannelMediumType::lan8032)
1016f71444daSRajashekar Gade Reddy         {
1017f71444daSRajashekar Gade Reddy             count++;
1018f71444daSRajashekar Gade Reddy         }
1019f71444daSRajashekar Gade Reddy         ch++;
1020f71444daSRajashekar Gade Reddy     }
1021f71444daSRajashekar Gade Reddy     return count * session::maxSessionCountPerChannel;
1022f71444daSRajashekar Gade Reddy }
1023f71444daSRajashekar Gade Reddy 
1024f71444daSRajashekar Gade Reddy /**
1025f71444daSRajashekar Gade Reddy  * @brief get session info request data.
1026f71444daSRajashekar Gade Reddy  *
1027f71444daSRajashekar Gade Reddy  * This function validates the request data and retrive request session id,
1028f71444daSRajashekar Gade Reddy  * session handle.
1029f71444daSRajashekar Gade Reddy  *
10304d22640aSRajashekar Gade Reddy  * @param[in] ctx - context of current session.
1031f71444daSRajashekar Gade Reddy  * @param[in] sessionIndex - request session index
1032f71444daSRajashekar Gade Reddy  * @param[in] payload - input payload
1033f71444daSRajashekar Gade Reddy  * @param[in] reqSessionId - unpacked session Id will be asigned
1034f71444daSRajashekar Gade Reddy  * @param[in] reqSessionHandle - unpacked session handle will be asigned
1035f71444daSRajashekar Gade Reddy  *
1036f71444daSRajashekar Gade Reddy  * @return success completion code if request data is valid
1037f71444daSRajashekar Gade Reddy  * else return the correcponding error completion code.
1038f71444daSRajashekar Gade Reddy  **/
getSessionInfoRequestData(const ipmi::Context::ptr ctx,const uint8_t sessionIndex,ipmi::message::Payload & payload,uint32_t & reqSessionId,uint8_t & reqSessionHandle)10391318a5edSPatrick Williams uint8_t getSessionInfoRequestData(
10401318a5edSPatrick Williams     const ipmi::Context::ptr ctx, const uint8_t sessionIndex,
10411318a5edSPatrick Williams     ipmi::message::Payload& payload, uint32_t& reqSessionId,
1042f71444daSRajashekar Gade Reddy     uint8_t& reqSessionHandle)
1043f71444daSRajashekar Gade Reddy {
10444d22640aSRajashekar Gade Reddy     if ((sessionIndex > session::maxSessionCountPerChannel) &&
10454d22640aSRajashekar Gade Reddy         (sessionIndex < session::searchSessionByHandle))
1046f71444daSRajashekar Gade Reddy     {
1047f71444daSRajashekar Gade Reddy         return ipmi::ccInvalidFieldRequest;
1048f71444daSRajashekar Gade Reddy     }
1049f71444daSRajashekar Gade Reddy 
1050f71444daSRajashekar Gade Reddy     switch (sessionIndex)
1051f71444daSRajashekar Gade Reddy     {
10524d22640aSRajashekar Gade Reddy         case session::searchCurrentSession:
10534d22640aSRajashekar Gade Reddy 
10544d22640aSRajashekar Gade Reddy             ipmi::ChannelInfo chInfo;
10554d22640aSRajashekar Gade Reddy             ipmi::getChannelInfo(ctx->channel, chInfo);
10564d22640aSRajashekar Gade Reddy 
10574d22640aSRajashekar Gade Reddy             if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) !=
10584d22640aSRajashekar Gade Reddy                 ipmi::EChannelMediumType::lan8032)
10594d22640aSRajashekar Gade Reddy             {
10604d22640aSRajashekar Gade Reddy                 return ipmi::ccInvalidFieldRequest;
10614d22640aSRajashekar Gade Reddy             }
10624d22640aSRajashekar Gade Reddy 
10634d22640aSRajashekar Gade Reddy             if (!payload.fullyUnpacked())
10644d22640aSRajashekar Gade Reddy             {
10654d22640aSRajashekar Gade Reddy                 return ipmi::ccReqDataLenInvalid;
10664d22640aSRajashekar Gade Reddy             }
10674d22640aSRajashekar Gade Reddy             // Check if current sessionId is 0, sessionId 0 is reserved.
10684d22640aSRajashekar Gade Reddy             if (ctx->sessionId == session::sessionZero)
10694d22640aSRajashekar Gade Reddy             {
10704d22640aSRajashekar Gade Reddy                 return session::ccInvalidSessionId;
10714d22640aSRajashekar Gade Reddy             }
10724d22640aSRajashekar Gade Reddy             reqSessionId = ctx->sessionId;
10734d22640aSRajashekar Gade Reddy             break;
10744d22640aSRajashekar Gade Reddy 
1075f71444daSRajashekar Gade Reddy         case session::searchSessionByHandle:
1076f71444daSRajashekar Gade Reddy 
1077f71444daSRajashekar Gade Reddy             if ((payload.unpack(reqSessionHandle)) ||
1078f71444daSRajashekar Gade Reddy                 (!payload.fullyUnpacked()))
1079f71444daSRajashekar Gade Reddy             {
1080f71444daSRajashekar Gade Reddy                 return ipmi::ccReqDataLenInvalid;
1081f71444daSRajashekar Gade Reddy             }
1082f71444daSRajashekar Gade Reddy 
1083f71444daSRajashekar Gade Reddy             if ((reqSessionHandle == session::sessionZero) ||
1084f71444daSRajashekar Gade Reddy                 ((reqSessionHandle & session::multiIntfaceSessionHandleMask) >
1085f71444daSRajashekar Gade Reddy                  session::maxSessionCountPerChannel))
1086f71444daSRajashekar Gade Reddy             {
1087f71444daSRajashekar Gade Reddy                 return session::ccInvalidSessionHandle;
1088f71444daSRajashekar Gade Reddy             }
1089f71444daSRajashekar Gade Reddy             break;
1090f71444daSRajashekar Gade Reddy 
1091f71444daSRajashekar Gade Reddy         case session::searchSessionById:
1092f71444daSRajashekar Gade Reddy 
1093f71444daSRajashekar Gade Reddy             if ((payload.unpack(reqSessionId)) || (!payload.fullyUnpacked()))
1094f71444daSRajashekar Gade Reddy             {
1095f71444daSRajashekar Gade Reddy                 return ipmi::ccReqDataLenInvalid;
1096f71444daSRajashekar Gade Reddy             }
1097f71444daSRajashekar Gade Reddy 
1098f71444daSRajashekar Gade Reddy             if (reqSessionId == session::sessionZero)
1099f71444daSRajashekar Gade Reddy             {
1100f71444daSRajashekar Gade Reddy                 return session::ccInvalidSessionId;
1101f71444daSRajashekar Gade Reddy             }
1102f71444daSRajashekar Gade Reddy             break;
1103f71444daSRajashekar Gade Reddy 
1104f71444daSRajashekar Gade Reddy         default:
1105f71444daSRajashekar Gade Reddy             if (!payload.fullyUnpacked())
1106f71444daSRajashekar Gade Reddy             {
1107f71444daSRajashekar Gade Reddy                 return ipmi::ccReqDataLenInvalid;
1108f71444daSRajashekar Gade Reddy             }
1109f71444daSRajashekar Gade Reddy             break;
1110f71444daSRajashekar Gade Reddy     }
1111f71444daSRajashekar Gade Reddy     return ipmi::ccSuccess;
1112f71444daSRajashekar Gade Reddy }
1113f71444daSRajashekar Gade Reddy 
getSessionState(ipmi::Context::ptr ctx,const std::string & service,const std::string & objPath,uint8_t & sessionState)1114e7e8b816SVernon Mauery uint8_t getSessionState(ipmi::Context::ptr ctx, const std::string& service,
1115e7e8b816SVernon Mauery                         const std::string& objPath, uint8_t& sessionState)
1116f71444daSRajashekar Gade Reddy {
1117e7e8b816SVernon Mauery     boost::system::error_code ec = ipmi::getDbusProperty(
1118e7e8b816SVernon Mauery         ctx, service, objPath, session::sessionIntf, "State", sessionState);
1119e7e8b816SVernon Mauery     if (ec)
1120f71444daSRajashekar Gade Reddy     {
112124fffdc8SGeorge Liu         lg2::error("Failed to fetch state property, service: {SERVICE}, "
112224fffdc8SGeorge Liu                    "object path: {OBJECTPATH}, interface: {INTERFACE}, "
112324fffdc8SGeorge Liu                    "error: {ERROR}",
112424fffdc8SGeorge Liu                    "SERVICE", service, "OBJECTPATH", objPath, "INTERFACE",
112524fffdc8SGeorge Liu                    session::sessionIntf, "ERROR", ec.message());
1126f71444daSRajashekar Gade Reddy         return ipmi::ccUnspecifiedError;
1127f71444daSRajashekar Gade Reddy     }
1128f71444daSRajashekar Gade Reddy     return ipmi::ccSuccess;
1129f71444daSRajashekar Gade Reddy }
1130f71444daSRajashekar Gade Reddy 
1131f71444daSRajashekar Gade Reddy static constexpr uint8_t macAddrLen = 6;
1132e7e8b816SVernon Mauery /** Alias SessionDetails - contain the optional information about an
1133e7e8b816SVernon Mauery  *        RMCP+ session.
1134e7e8b816SVernon Mauery  *
1135e7e8b816SVernon Mauery  *  @param userID - uint6_t session user ID (0-63)
1136e7e8b816SVernon Mauery  *  @param reserved - uint2_t reserved
1137e7e8b816SVernon Mauery  *  @param privilege - uint4_t session privilege (0-5)
1138e7e8b816SVernon Mauery  *  @param reserved - uint4_t reserved
1139e7e8b816SVernon Mauery  *  @param channel - uint4_t session channel number
1140e7e8b816SVernon Mauery  *  @param protocol - uint4_t session protocol
1141e7e8b816SVernon Mauery  *  @param remoteIP - uint32_t remote IP address
1142e7e8b816SVernon Mauery  *  @param macAddr - std::array<uint8_t, 6> mac address
1143e7e8b816SVernon Mauery  *  @param port - uint16_t remote port
1144e7e8b816SVernon Mauery  */
1145e7e8b816SVernon Mauery using SessionDetails =
1146e7e8b816SVernon Mauery     std::tuple<uint2_t, uint6_t, uint4_t, uint4_t, uint4_t, uint4_t, uint32_t,
1147e7e8b816SVernon Mauery                std::array<uint8_t, macAddrLen>, uint16_t>;
1148f71444daSRajashekar Gade Reddy 
1149e7e8b816SVernon Mauery /** @brief get session details for a given session
1150e7e8b816SVernon Mauery  *
1151e7e8b816SVernon Mauery  *  @param[in] ctx - ipmi::Context pointer for accessing D-Bus
1152e7e8b816SVernon Mauery  *  @param[in] service - D-Bus service name to fetch details from
1153e7e8b816SVernon Mauery  *  @param[in] objPath - D-Bus object path for session
1154e7e8b816SVernon Mauery  *  @param[out] sessionHandle - return session handle for session
1155e7e8b816SVernon Mauery  *  @param[out] sessionState - return session state for session
1156e7e8b816SVernon Mauery  *  @param[out] details - return a SessionDetails tuple containing other
1157e7e8b816SVernon Mauery  *                        session info
1158e7e8b816SVernon Mauery  *  @return - ipmi::Cc success or error code
1159e7e8b816SVernon Mauery  */
getSessionDetails(ipmi::Context::ptr ctx,const std::string & service,const std::string & objPath,uint8_t & sessionHandle,uint8_t & sessionState,SessionDetails & details)1160e7e8b816SVernon Mauery ipmi::Cc getSessionDetails(ipmi::Context::ptr ctx, const std::string& service,
1161e7e8b816SVernon Mauery                            const std::string& objPath, uint8_t& sessionHandle,
1162e7e8b816SVernon Mauery                            uint8_t& sessionState, SessionDetails& details)
1163f71444daSRajashekar Gade Reddy {
1164e7e8b816SVernon Mauery     ipmi::PropertyMap sessionProps;
1165e7e8b816SVernon Mauery     boost::system::error_code ec = ipmi::getAllDbusProperties(
1166e7e8b816SVernon Mauery         ctx, service, objPath, session::sessionIntf, sessionProps);
1167f71444daSRajashekar Gade Reddy 
1168e7e8b816SVernon Mauery     if (ec)
1169f71444daSRajashekar Gade Reddy     {
117024fffdc8SGeorge Liu         lg2::error("Failed to fetch state property, service: {SERVICE}, "
117124fffdc8SGeorge Liu                    "object path: {OBJECTPATH}, interface: {INTERFACE}, "
117224fffdc8SGeorge Liu                    "error: {ERROR}",
117324fffdc8SGeorge Liu                    "SERVICE", service, "OBJECTPATH", objPath, "INTERFACE",
117424fffdc8SGeorge Liu                    session::sessionIntf, "ERROR", ec.message());
1175f71444daSRajashekar Gade Reddy         return ipmi::ccUnspecifiedError;
1176f71444daSRajashekar Gade Reddy     }
1177f71444daSRajashekar Gade Reddy 
1178e7e8b816SVernon Mauery     sessionState = ipmi::mappedVariant<uint8_t>(
1179e7e8b816SVernon Mauery         sessionProps, "State", static_cast<uint8_t>(session::State::inactive));
1180e7e8b816SVernon Mauery     if (sessionState == static_cast<uint8_t>(session::State::active))
1181e7e8b816SVernon Mauery     {
11821318a5edSPatrick Williams         sessionHandle =
11831318a5edSPatrick Williams             ipmi::mappedVariant<uint8_t>(sessionProps, "SessionHandle", 0);
11841318a5edSPatrick Williams         std::get<0>(details) =
11851318a5edSPatrick Williams             ipmi::mappedVariant<uint8_t>(sessionProps, "UserID", 0xff);
1186e7e8b816SVernon Mauery         // std::get<1>(details) = 0; // (default constructed to 0)
1187e7e8b816SVernon Mauery         std::get<2>(details) =
1188e7e8b816SVernon Mauery             ipmi::mappedVariant<uint8_t>(sessionProps, "CurrentPrivilege", 0);
1189e7e8b816SVernon Mauery         // std::get<3>(details) = 0; // (default constructed to 0)
11901318a5edSPatrick Williams         std::get<4>(details) =
11911318a5edSPatrick Williams             ipmi::mappedVariant<uint8_t>(sessionProps, "ChannelNum", 0xff);
1192e7e8b816SVernon Mauery         constexpr uint4_t rmcpPlusProtocol = 1;
1193e7e8b816SVernon Mauery         std::get<5>(details) = rmcpPlusProtocol;
11941318a5edSPatrick Williams         std::get<6>(details) =
11951318a5edSPatrick Williams             ipmi::mappedVariant<uint32_t>(sessionProps, "RemoteIPAddr", 0);
1196e7e8b816SVernon Mauery         // std::get<7>(details) = {{0}}; // default constructed to all 0
11971318a5edSPatrick Williams         std::get<8>(details) =
11981318a5edSPatrick Williams             ipmi::mappedVariant<uint16_t>(sessionProps, "RemotePort", 0);
1199e7e8b816SVernon Mauery     }
1200e7e8b816SVernon Mauery 
1201f71444daSRajashekar Gade Reddy     return ipmi::ccSuccess;
1202f71444daSRajashekar Gade Reddy }
1203f71444daSRajashekar Gade Reddy 
1204e7e8b816SVernon Mauery ipmi::RspType<uint8_t, // session handle,
1205f71444daSRajashekar Gade Reddy               uint8_t, // total session count
1206f71444daSRajashekar Gade Reddy               uint8_t, // active session count
1207e7e8b816SVernon Mauery               std::optional<SessionDetails>>
ipmiAppGetSessionInfo(ipmi::Context::ptr ctx,uint8_t sessionIndex,ipmi::message::Payload & payload)12084d22640aSRajashekar Gade Reddy     ipmiAppGetSessionInfo(ipmi::Context::ptr ctx, uint8_t sessionIndex,
12094d22640aSRajashekar Gade Reddy                           ipmi::message::Payload& payload)
1210f71444daSRajashekar Gade Reddy {
1211f71444daSRajashekar Gade Reddy     uint32_t reqSessionId = 0;
1212f71444daSRajashekar Gade Reddy     uint8_t reqSessionHandle = session::defaultSessionHandle;
1213f71444daSRajashekar Gade Reddy     // initializing state to 0xff as 0 represents state as inactive.
1214f71444daSRajashekar Gade Reddy     uint8_t state = 0xFF;
1215f71444daSRajashekar Gade Reddy 
1216f71444daSRajashekar Gade Reddy     uint8_t completionCode = getSessionInfoRequestData(
12174d22640aSRajashekar Gade Reddy         ctx, sessionIndex, payload, reqSessionId, reqSessionHandle);
1218f71444daSRajashekar Gade Reddy 
1219f71444daSRajashekar Gade Reddy     if (completionCode)
1220f71444daSRajashekar Gade Reddy     {
1221f71444daSRajashekar Gade Reddy         return ipmi::response(completionCode);
1222f71444daSRajashekar Gade Reddy     }
1223e7e8b816SVernon Mauery     ipmi::ObjectTree objectTree;
1224e7e8b816SVernon Mauery     boost::system::error_code ec = ipmi::getAllDbusObjects(
1225e7e8b816SVernon Mauery         ctx, session::sessionManagerRootPath, session::sessionIntf, objectTree);
1226e7e8b816SVernon Mauery     if (ec)
1227f71444daSRajashekar Gade Reddy     {
122824fffdc8SGeorge Liu         lg2::error("Failed to fetch object from dbus, "
122924fffdc8SGeorge Liu                    "interface: {INTERFACE}, error: {ERROR}",
123024fffdc8SGeorge Liu                    "INTERFACE", session::sessionIntf, "ERROR", ec.message());
1231e7e8b816SVernon Mauery         return ipmi::responseUnspecifiedError();
1232e7e8b816SVernon Mauery     }
1233f71444daSRajashekar Gade Reddy 
1234e7e8b816SVernon Mauery     uint8_t totalSessionCount = getTotalSessionCount();
1235e7e8b816SVernon Mauery     uint8_t activeSessionCount = 0;
1236e7e8b816SVernon Mauery     uint8_t sessionHandle = session::defaultSessionHandle;
1237ca93bb10SJohnathan Mantey     uint8_t activeSessionHandle = 0;
1238e7e8b816SVernon Mauery     std::optional<SessionDetails> maybeDetails;
1239e7e8b816SVernon Mauery     uint8_t index = 0;
1240f71444daSRajashekar Gade Reddy     for (auto& objectTreeItr : objectTree)
1241f71444daSRajashekar Gade Reddy     {
1242f71444daSRajashekar Gade Reddy         uint32_t sessionId = 0;
1243f71444daSRajashekar Gade Reddy         std::string objectPath = objectTreeItr.first;
1244f71444daSRajashekar Gade Reddy 
1245f71444daSRajashekar Gade Reddy         if (!parseCloseSessionInputPayload(objectPath, sessionId,
1246f71444daSRajashekar Gade Reddy                                            sessionHandle))
1247f71444daSRajashekar Gade Reddy         {
1248f71444daSRajashekar Gade Reddy             continue;
1249f71444daSRajashekar Gade Reddy         }
1250f71444daSRajashekar Gade Reddy         index++;
1251f71444daSRajashekar Gade Reddy         auto& serviceMap = objectTreeItr.second;
1252f71444daSRajashekar Gade Reddy         auto itr = serviceMap.begin();
1253f71444daSRajashekar Gade Reddy 
1254f71444daSRajashekar Gade Reddy         if (serviceMap.size() != 1)
1255f71444daSRajashekar Gade Reddy         {
1256f71444daSRajashekar Gade Reddy             return ipmi::responseUnspecifiedError();
1257f71444daSRajashekar Gade Reddy         }
1258f71444daSRajashekar Gade Reddy 
1259f71444daSRajashekar Gade Reddy         std::string service = itr->first;
1260f71444daSRajashekar Gade Reddy         uint8_t sessionState = 0;
12611318a5edSPatrick Williams         completionCode =
12621318a5edSPatrick Williams             getSessionState(ctx, service, objectPath, sessionState);
1263f71444daSRajashekar Gade Reddy         if (completionCode)
1264f71444daSRajashekar Gade Reddy         {
1265f71444daSRajashekar Gade Reddy             return ipmi::response(completionCode);
1266f71444daSRajashekar Gade Reddy         }
1267f71444daSRajashekar Gade Reddy 
1268f71444daSRajashekar Gade Reddy         if (sessionState == static_cast<uint8_t>(session::State::active))
1269f71444daSRajashekar Gade Reddy         {
1270e7e8b816SVernon Mauery             activeSessionCount++;
1271f71444daSRajashekar Gade Reddy         }
1272f71444daSRajashekar Gade Reddy 
1273ca93bb10SJohnathan Mantey         if (index == sessionIndex || reqSessionId == sessionId ||
1274ca93bb10SJohnathan Mantey             reqSessionHandle == sessionHandle)
1275f71444daSRajashekar Gade Reddy         {
1276e7e8b816SVernon Mauery             SessionDetails details{};
1277e7e8b816SVernon Mauery             completionCode = getSessionDetails(ctx, service, objectPath,
1278e7e8b816SVernon Mauery                                                sessionHandle, state, details);
1279f71444daSRajashekar Gade Reddy 
1280f71444daSRajashekar Gade Reddy             if (completionCode)
1281f71444daSRajashekar Gade Reddy             {
1282f71444daSRajashekar Gade Reddy                 return ipmi::response(completionCode);
1283f71444daSRajashekar Gade Reddy             }
1284ca93bb10SJohnathan Mantey             activeSessionHandle = sessionHandle;
1285e7e8b816SVernon Mauery             maybeDetails = std::move(details);
1286ca93bb10SJohnathan Mantey         }
1287f71444daSRajashekar Gade Reddy     }
1288f71444daSRajashekar Gade Reddy 
1289e7e8b816SVernon Mauery     if (state == static_cast<uint8_t>(session::State::active) ||
1290e7e8b816SVernon Mauery         state == static_cast<uint8_t>(session::State::tearDownInProgress))
1291f71444daSRajashekar Gade Reddy     {
1292ca93bb10SJohnathan Mantey         return ipmi::responseSuccess(activeSessionHandle, totalSessionCount,
1293e7e8b816SVernon Mauery                                      activeSessionCount, maybeDetails);
1294f71444daSRajashekar Gade Reddy     }
1295f71444daSRajashekar Gade Reddy 
1296f71444daSRajashekar Gade Reddy     return ipmi::responseInvalidFieldRequest();
1297f71444daSRajashekar Gade Reddy }
1298f71444daSRajashekar Gade Reddy 
getSysFWVersion(ipmi::Context::ptr & ctx)1299a809fa55SThang Tran std::optional<std::string> getSysFWVersion(ipmi::Context::ptr& ctx)
1300a809fa55SThang Tran {
1301a809fa55SThang Tran     /*
1302a809fa55SThang Tran      * The System Firmware version is detected via following steps:
1303a809fa55SThang Tran      * - Get all of object paths that include
1304a809fa55SThang Tran      * "xyz.openbmc_project.Software.Version" interface.
1305a809fa55SThang Tran      * - Get the Purpose property of above object paths.
1306a809fa55SThang Tran      * - If the Purpose is Host then get the Version property.
1307a809fa55SThang Tran      */
1308a809fa55SThang Tran     ipmi::ObjectTree objectTree;
1309a809fa55SThang Tran     boost::system::error_code ec =
1310a809fa55SThang Tran         ipmi::getAllDbusObjects(ctx, softwareRoot, versionIntf, objectTree);
1311a809fa55SThang Tran     if (ec.value())
1312a809fa55SThang Tran     {
1313a809fa55SThang Tran         return std::nullopt;
1314a809fa55SThang Tran     }
1315a809fa55SThang Tran 
1316a809fa55SThang Tran     for (const auto& [objPath, serviceMap] : objectTree)
1317a809fa55SThang Tran     {
1318a809fa55SThang Tran         for (const auto& [service, intfs] : serviceMap)
1319a809fa55SThang Tran         {
1320a809fa55SThang Tran             ipmi::PropertyMap props;
1321a809fa55SThang Tran             ec = ipmi::getAllDbusProperties(ctx, service, objPath, versionIntf,
1322a809fa55SThang Tran                                             props);
1323a809fa55SThang Tran             if (ec.value())
1324a809fa55SThang Tran             {
1325a809fa55SThang Tran                 continue;
1326a809fa55SThang Tran             }
1327a809fa55SThang Tran 
1328a809fa55SThang Tran             std::string purposeProp = std::string(
1329a809fa55SThang Tran                 ipmi::mappedVariant<std::string>(props, "Purpose", ""));
1330a809fa55SThang Tran 
1331a809fa55SThang Tran             if (!purposeProp.ends_with(versionPurposeHostEnd))
1332a809fa55SThang Tran             {
1333a809fa55SThang Tran                 continue;
1334a809fa55SThang Tran             }
1335a809fa55SThang Tran 
1336a809fa55SThang Tran             std::string sysFWVersion = std::string(
1337a809fa55SThang Tran                 ipmi::mappedVariant<std::string>(props, "Version", ""));
1338a809fa55SThang Tran 
1339a809fa55SThang Tran             if (sysFWVersion.empty())
1340a809fa55SThang Tran             {
1341a809fa55SThang Tran                 return std::nullopt;
1342a809fa55SThang Tran             }
1343a809fa55SThang Tran 
1344a809fa55SThang Tran             return sysFWVersion;
1345a809fa55SThang Tran         }
1346a809fa55SThang Tran     }
1347a809fa55SThang Tran 
1348a809fa55SThang Tran     return std::nullopt;
1349a809fa55SThang Tran }
1350a809fa55SThang Tran 
1351f542e8b0SXo Wang static std::unique_ptr<SysInfoParamStore> sysInfoParamStore;
1352f542e8b0SXo Wang 
sysInfoReadSystemName()135387651333SXo Wang static std::string sysInfoReadSystemName()
135487651333SXo Wang {
135587651333SXo Wang     // Use the BMC hostname as the "System Name."
135687651333SXo Wang     char hostname[HOST_NAME_MAX + 1] = {};
135787651333SXo Wang     if (gethostname(hostname, HOST_NAME_MAX) != 0)
135887651333SXo Wang     {
135987651333SXo Wang         perror("System info parameter: system name");
136087651333SXo Wang     }
136187651333SXo Wang     return hostname;
136287651333SXo Wang }
136387651333SXo Wang 
136498b43babSJia, chunhui static constexpr uint8_t paramRevision = 0x11;
136598b43babSJia, chunhui static constexpr size_t configParameterLength = 16;
1366f542e8b0SXo Wang 
136798b43babSJia, chunhui static constexpr size_t smallChunkSize = 14;
136898b43babSJia, chunhui static constexpr size_t fullChunkSize = 16;
1369449f2166SJia, chunhui static constexpr uint8_t progressMask = 0x3;
137010752832Skrishnar4 static constexpr uint8_t maxValidEncodingData = 0x02;
137198b43babSJia, chunhui 
137298b43babSJia, chunhui static constexpr uint8_t setComplete = 0x0;
137398b43babSJia, chunhui static constexpr uint8_t setInProgress = 0x1;
137498b43babSJia, chunhui static uint8_t transferStatus = setComplete;
137598b43babSJia, chunhui 
1376449f2166SJia, chunhui static constexpr uint8_t configDataOverhead = 2;
1377449f2166SJia, chunhui 
137898b43babSJia, chunhui namespace ipmi
1379f542e8b0SXo Wang {
138098b43babSJia, chunhui constexpr Cc ccParmNotSupported = 0x80;
1381449f2166SJia, chunhui constexpr Cc ccSetInProgressActive = 0x81;
138298b43babSJia, chunhui 
responseParmNotSupported()138398b43babSJia, chunhui static inline auto responseParmNotSupported()
1384f542e8b0SXo Wang {
138598b43babSJia, chunhui     return response(ccParmNotSupported);
1386f542e8b0SXo Wang }
responseSetInProgressActive()1387449f2166SJia, chunhui static inline auto responseSetInProgressActive()
1388449f2166SJia, chunhui {
1389449f2166SJia, chunhui     return response(ccSetInProgressActive);
1390449f2166SJia, chunhui }
139198b43babSJia, chunhui } // namespace ipmi
139298b43babSJia, chunhui 
1393449f2166SJia, chunhui ipmi::RspType<uint8_t,                // Parameter revision
139498b43babSJia, chunhui               std::optional<uint8_t>, // data1 / setSelector / ProgressStatus
1395449f2166SJia, chunhui               std::optional<std::vector<uint8_t>>> // data2-17
ipmiAppGetSystemInfo(ipmi::Context::ptr ctx,uint7_t reserved,bool getRevision,uint8_t paramSelector,uint8_t setSelector,uint8_t BlockSelector)1396a809fa55SThang Tran     ipmiAppGetSystemInfo(ipmi::Context::ptr ctx, uint7_t reserved,
1397a809fa55SThang Tran                          bool getRevision, uint8_t paramSelector,
1398a809fa55SThang Tran                          uint8_t setSelector, uint8_t BlockSelector)
1399f542e8b0SXo Wang {
1400a5ae7728SSnehalatha V     if (reserved || (paramSelector >= invalidParamSelectorStart &&
1401a5ae7728SSnehalatha V                      paramSelector <= invalidParamSelectorEnd))
1402c2566a93Sjayaprakash Mutyala     {
1403c2566a93Sjayaprakash Mutyala         return ipmi::responseInvalidFieldRequest();
1404c2566a93Sjayaprakash Mutyala     }
14053771f5f2SPavanKumarIntel     if (paramSelector >= oemCmdStart)
1406a5ae7728SSnehalatha V     {
1407a5ae7728SSnehalatha V         return ipmi::responseParmNotSupported();
1408a5ae7728SSnehalatha V     }
1409c2566a93Sjayaprakash Mutyala     if (getRevision)
1410f542e8b0SXo Wang     {
141198b43babSJia, chunhui         return ipmi::responseSuccess(paramRevision, std::nullopt, std::nullopt);
1412f542e8b0SXo Wang     }
1413f542e8b0SXo Wang 
141498b43babSJia, chunhui     if (paramSelector == 0)
1415f542e8b0SXo Wang     {
141698b43babSJia, chunhui         return ipmi::responseSuccess(paramRevision, transferStatus,
141798b43babSJia, chunhui                                      std::nullopt);
1418f542e8b0SXo Wang     }
1419f542e8b0SXo Wang 
142098b43babSJia, chunhui     if (BlockSelector != 0) // 00h if parameter does not require a block number
1421f542e8b0SXo Wang     {
142298b43babSJia, chunhui         return ipmi::responseParmNotSupported();
1423f542e8b0SXo Wang     }
1424f542e8b0SXo Wang 
1425f542e8b0SXo Wang     if (sysInfoParamStore == nullptr)
1426f542e8b0SXo Wang     {
1427f542e8b0SXo Wang         sysInfoParamStore = std::make_unique<SysInfoParamStore>();
142887651333SXo Wang         sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME,
142987651333SXo Wang                                   sysInfoReadSystemName);
1430f542e8b0SXo Wang     }
1431f542e8b0SXo Wang 
1432a809fa55SThang Tran     if (paramSelector == IPMI_SYSINFO_SYSTEM_FW_VERSION)
1433a809fa55SThang Tran     {
1434a809fa55SThang Tran         auto fwVersion = getSysFWVersion(ctx);
1435a809fa55SThang Tran 
1436a809fa55SThang Tran         if (fwVersion == std::nullopt)
1437a809fa55SThang Tran         {
1438a809fa55SThang Tran             return ipmi::responseUnspecifiedError();
1439a809fa55SThang Tran         }
1440a809fa55SThang Tran         sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_FW_VERSION, *fwVersion);
1441a809fa55SThang Tran     }
1442a809fa55SThang Tran 
1443f542e8b0SXo Wang     // Parameters other than Set In Progress are assumed to be strings.
144498b43babSJia, chunhui     std::tuple<bool, std::string> ret =
144598b43babSJia, chunhui         sysInfoParamStore->lookup(paramSelector);
144698b43babSJia, chunhui     bool found = std::get<0>(ret);
1447f542e8b0SXo Wang     if (!found)
1448f542e8b0SXo Wang     {
1449a5ae7728SSnehalatha V         return ipmi::responseSensorInvalid();
1450f542e8b0SXo Wang     }
145198b43babSJia, chunhui     std::string& paramString = std::get<1>(ret);
1452449f2166SJia, chunhui     std::vector<uint8_t> configData;
145398b43babSJia, chunhui     size_t count = 0;
145498b43babSJia, chunhui     if (setSelector == 0)
145598b43babSJia, chunhui     {                               // First chunk has only 14 bytes.
1456449f2166SJia, chunhui         configData.emplace_back(0); // encoding
1457449f2166SJia, chunhui         configData.emplace_back(paramString.length()); // string length
1458449f2166SJia, chunhui         count = std::min(paramString.length(), smallChunkSize);
1459449f2166SJia, chunhui         configData.resize(count + configDataOverhead);
146098b43babSJia, chunhui         std::copy_n(paramString.begin(), count,
1461a5ae7728SSnehalatha V                     configData.begin() + configDataOverhead); // 14 bytes chunk
1462a5ae7728SSnehalatha V 
1463a5ae7728SSnehalatha V         // Append zero's to remaining bytes
1464a5ae7728SSnehalatha V         if (configData.size() < configParameterLength)
1465a5ae7728SSnehalatha V         {
1466a5ae7728SSnehalatha V             std::fill_n(std::back_inserter(configData),
1467a5ae7728SSnehalatha V                         configParameterLength - configData.size(), 0x00);
1468a5ae7728SSnehalatha V         }
146998b43babSJia, chunhui     }
147098b43babSJia, chunhui     else
1471f542e8b0SXo Wang     {
1472449f2166SJia, chunhui         size_t offset = (setSelector * fullChunkSize) - configDataOverhead;
147398b43babSJia, chunhui         if (offset >= paramString.length())
147498b43babSJia, chunhui         {
147598b43babSJia, chunhui             return ipmi::responseParmOutOfRange();
1476f542e8b0SXo Wang         }
1477449f2166SJia, chunhui         count = std::min(paramString.length() - offset, fullChunkSize);
1478449f2166SJia, chunhui         configData.resize(count);
147998b43babSJia, chunhui         std::copy_n(paramString.begin() + offset, count,
148098b43babSJia, chunhui                     configData.begin()); // 16 bytes chunk
148198b43babSJia, chunhui     }
148298b43babSJia, chunhui     return ipmi::responseSuccess(paramRevision, setSelector, configData);
1483f542e8b0SXo Wang }
1484f542e8b0SXo Wang 
ipmiAppSetSystemInfo(uint8_t paramSelector,uint8_t data1,std::vector<uint8_t> configData)1485449f2166SJia, chunhui ipmi::RspType<> ipmiAppSetSystemInfo(uint8_t paramSelector, uint8_t data1,
1486449f2166SJia, chunhui                                      std::vector<uint8_t> configData)
1487449f2166SJia, chunhui {
14883c5e413bSjayaprakash Mutyala     if (paramSelector >= invalidParamSelectorStart &&
14893c5e413bSjayaprakash Mutyala         paramSelector <= invalidParamSelectorEnd)
14903c5e413bSjayaprakash Mutyala     {
14913c5e413bSjayaprakash Mutyala         return ipmi::responseInvalidFieldRequest();
14923c5e413bSjayaprakash Mutyala     }
14933771f5f2SPavanKumarIntel     if (paramSelector >= oemCmdStart)
14943c5e413bSjayaprakash Mutyala     {
14953c5e413bSjayaprakash Mutyala         return ipmi::responseParmNotSupported();
14963c5e413bSjayaprakash Mutyala     }
14973c5e413bSjayaprakash Mutyala 
1498449f2166SJia, chunhui     if (paramSelector == 0)
1499449f2166SJia, chunhui     {
1500449f2166SJia, chunhui         // attempt to set the 'set in progress' value (in parameter #0)
1501449f2166SJia, chunhui         // when not in the set complete state.
1502449f2166SJia, chunhui         if ((transferStatus != setComplete) && (data1 == setInProgress))
1503449f2166SJia, chunhui         {
1504449f2166SJia, chunhui             return ipmi::responseSetInProgressActive();
1505449f2166SJia, chunhui         }
1506449f2166SJia, chunhui         // only following 2 states are supported
1507449f2166SJia, chunhui         if (data1 > setInProgress)
1508449f2166SJia, chunhui         {
150924fffdc8SGeorge Liu             lg2::error("illegal SetInProgress status");
1510449f2166SJia, chunhui             return ipmi::responseInvalidFieldRequest();
1511449f2166SJia, chunhui         }
1512449f2166SJia, chunhui 
1513449f2166SJia, chunhui         transferStatus = data1 & progressMask;
1514449f2166SJia, chunhui         return ipmi::responseSuccess();
1515449f2166SJia, chunhui     }
1516449f2166SJia, chunhui 
1517449f2166SJia, chunhui     if (configData.size() > configParameterLength)
1518449f2166SJia, chunhui     {
1519449f2166SJia, chunhui         return ipmi::responseInvalidFieldRequest();
1520449f2166SJia, chunhui     }
1521449f2166SJia, chunhui 
15223c5e413bSjayaprakash Mutyala     // Append zero's to remaining bytes
15233c5e413bSjayaprakash Mutyala     if (configData.size() < configParameterLength)
15243c5e413bSjayaprakash Mutyala     {
15253c5e413bSjayaprakash Mutyala         fill_n(back_inserter(configData),
15263c5e413bSjayaprakash Mutyala                (configParameterLength - configData.size()), 0x00);
15273c5e413bSjayaprakash Mutyala     }
15283c5e413bSjayaprakash Mutyala 
1529449f2166SJia, chunhui     if (!sysInfoParamStore)
1530449f2166SJia, chunhui     {
1531449f2166SJia, chunhui         sysInfoParamStore = std::make_unique<SysInfoParamStore>();
1532449f2166SJia, chunhui         sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME,
1533449f2166SJia, chunhui                                   sysInfoReadSystemName);
1534449f2166SJia, chunhui     }
1535449f2166SJia, chunhui 
1536449f2166SJia, chunhui     // lookup
1537449f2166SJia, chunhui     std::tuple<bool, std::string> ret =
1538449f2166SJia, chunhui         sysInfoParamStore->lookup(paramSelector);
1539449f2166SJia, chunhui     bool found = std::get<0>(ret);
1540449f2166SJia, chunhui     std::string& paramString = std::get<1>(ret);
1541449f2166SJia, chunhui     if (!found)
1542449f2166SJia, chunhui     {
1543449f2166SJia, chunhui         // parameter does not exist. Init new
1544449f2166SJia, chunhui         paramString = "";
1545449f2166SJia, chunhui     }
1546449f2166SJia, chunhui 
1547449f2166SJia, chunhui     uint8_t setSelector = data1;
1548449f2166SJia, chunhui     size_t count = 0;
1549449f2166SJia, chunhui     if (setSelector == 0) // First chunk has only 14 bytes.
1550449f2166SJia, chunhui     {
155110752832Skrishnar4         uint8_t encoding = configData.at(0);
155210752832Skrishnar4         if (encoding > maxValidEncodingData)
155310752832Skrishnar4         {
155410752832Skrishnar4             return ipmi::responseInvalidFieldRequest();
155510752832Skrishnar4         }
155610752832Skrishnar4 
1557449f2166SJia, chunhui         size_t stringLen = configData.at(1); // string length
1558449f2166SJia, chunhui         count = std::min(stringLen, smallChunkSize);
1559449f2166SJia, chunhui         count = std::min(count, configData.size());
1560449f2166SJia, chunhui         paramString.resize(stringLen); // reserve space
1561449f2166SJia, chunhui         std::copy_n(configData.begin() + configDataOverhead, count,
1562449f2166SJia, chunhui                     paramString.begin());
1563449f2166SJia, chunhui     }
1564449f2166SJia, chunhui     else
1565449f2166SJia, chunhui     {
1566449f2166SJia, chunhui         size_t offset = (setSelector * fullChunkSize) - configDataOverhead;
1567449f2166SJia, chunhui         if (offset >= paramString.length())
1568449f2166SJia, chunhui         {
1569449f2166SJia, chunhui             return ipmi::responseParmOutOfRange();
1570449f2166SJia, chunhui         }
1571449f2166SJia, chunhui         count = std::min(paramString.length() - offset, configData.size());
1572449f2166SJia, chunhui         std::copy_n(configData.begin(), count, paramString.begin() + offset);
1573449f2166SJia, chunhui     }
1574449f2166SJia, chunhui     sysInfoParamStore->update(paramSelector, paramString);
1575449f2166SJia, chunhui     return ipmi::responseSuccess();
1576449f2166SJia, chunhui }
1577449f2166SJia, chunhui 
1578bd0503a7SYong Li #ifdef ENABLE_I2C_WHITELIST_CHECK
convertStringToData(const std::string & command)157984bf9be5SRichard Marian Thomaiyar inline std::vector<uint8_t> convertStringToData(const std::string& command)
158084bf9be5SRichard Marian Thomaiyar {
158184bf9be5SRichard Marian Thomaiyar     std::istringstream iss(command);
158284bf9be5SRichard Marian Thomaiyar     std::string token;
158384bf9be5SRichard Marian Thomaiyar     std::vector<uint8_t> dataValue;
158484bf9be5SRichard Marian Thomaiyar     while (std::getline(iss, token, ' '))
158584bf9be5SRichard Marian Thomaiyar     {
158684bf9be5SRichard Marian Thomaiyar         dataValue.emplace_back(
158784bf9be5SRichard Marian Thomaiyar             static_cast<uint8_t>(std::stoul(token, nullptr, base_16)));
158884bf9be5SRichard Marian Thomaiyar     }
158984bf9be5SRichard Marian Thomaiyar     return dataValue;
159084bf9be5SRichard Marian Thomaiyar }
159184bf9be5SRichard Marian Thomaiyar 
populateI2CControllerWRAllowlist()159268d9d405SMatt Simmering static bool populateI2CControllerWRAllowlist()
159384bf9be5SRichard Marian Thomaiyar {
159484bf9be5SRichard Marian Thomaiyar     nlohmann::json data = nullptr;
159568d9d405SMatt Simmering     std::ifstream jsonFile(i2cControllerWRAllowlistFile);
159684bf9be5SRichard Marian Thomaiyar 
159784bf9be5SRichard Marian Thomaiyar     if (!jsonFile.good())
159884bf9be5SRichard Marian Thomaiyar     {
159924fffdc8SGeorge Liu         lg2::warning("i2c allow list file not found! file name: {FILE_NAME}",
160024fffdc8SGeorge Liu                      "FILE_NAME", i2cControllerWRAllowlistFile);
160184bf9be5SRichard Marian Thomaiyar         return false;
160284bf9be5SRichard Marian Thomaiyar     }
160384bf9be5SRichard Marian Thomaiyar 
160484bf9be5SRichard Marian Thomaiyar     try
160584bf9be5SRichard Marian Thomaiyar     {
160684bf9be5SRichard Marian Thomaiyar         data = nlohmann::json::parse(jsonFile, nullptr, false);
160784bf9be5SRichard Marian Thomaiyar     }
1608a2ad2da8SPatrick Williams     catch (const nlohmann::json::parse_error& e)
160984bf9be5SRichard Marian Thomaiyar     {
161024fffdc8SGeorge Liu         lg2::error("Corrupted i2c allow list config file, "
161124fffdc8SGeorge Liu                    "file name: {FILE_NAME}, error: {ERROR}",
161224fffdc8SGeorge Liu                    "FILE_NAME", i2cControllerWRAllowlistFile, "ERROR", e);
161384bf9be5SRichard Marian Thomaiyar         return false;
161484bf9be5SRichard Marian Thomaiyar     }
161584bf9be5SRichard Marian Thomaiyar 
161684bf9be5SRichard Marian Thomaiyar     try
161784bf9be5SRichard Marian Thomaiyar     {
161884bf9be5SRichard Marian Thomaiyar         // Example JSON Structure format
161984bf9be5SRichard Marian Thomaiyar         // "filters": [
162084bf9be5SRichard Marian Thomaiyar         //    {
162184bf9be5SRichard Marian Thomaiyar         //      "Description": "Allow full read - ignore first byte write value
162284bf9be5SRichard Marian Thomaiyar         //      for 0x40 to 0x4F",
162384bf9be5SRichard Marian Thomaiyar         //      "busId": "0x01",
162484bf9be5SRichard Marian Thomaiyar         //      "slaveAddr": "0x40",
162584bf9be5SRichard Marian Thomaiyar         //      "slaveAddrMask": "0x0F",
162684bf9be5SRichard Marian Thomaiyar         //      "command": "0x00",
162784bf9be5SRichard Marian Thomaiyar         //      "commandMask": "0xFF"
162884bf9be5SRichard Marian Thomaiyar         //    },
162984bf9be5SRichard Marian Thomaiyar         //    {
163084bf9be5SRichard Marian Thomaiyar         //      "Description": "Allow full read - first byte match 0x05 and
163184bf9be5SRichard Marian Thomaiyar         //      ignore second byte",
163284bf9be5SRichard Marian Thomaiyar         //      "busId": "0x01",
163384bf9be5SRichard Marian Thomaiyar         //      "slaveAddr": "0x57",
163484bf9be5SRichard Marian Thomaiyar         //      "slaveAddrMask": "0x00",
163584bf9be5SRichard Marian Thomaiyar         //      "command": "0x05 0x00",
163684bf9be5SRichard Marian Thomaiyar         //      "commandMask": "0x00 0xFF"
163784bf9be5SRichard Marian Thomaiyar         //    },]
163884bf9be5SRichard Marian Thomaiyar 
163984bf9be5SRichard Marian Thomaiyar         nlohmann::json filters = data[filtersStr].get<nlohmann::json>();
164068d9d405SMatt Simmering         std::vector<i2cControllerWRAllowlist>& allowlist = getWRAllowlist();
164184bf9be5SRichard Marian Thomaiyar         for (const auto& it : filters.items())
164284bf9be5SRichard Marian Thomaiyar         {
164384bf9be5SRichard Marian Thomaiyar             nlohmann::json filter = it.value();
164484bf9be5SRichard Marian Thomaiyar             if (filter.is_null())
164584bf9be5SRichard Marian Thomaiyar             {
164624fffdc8SGeorge Liu                 lg2::error(
164724fffdc8SGeorge Liu                     "Corrupted I2C controller write read allowlist config file, "
164824fffdc8SGeorge Liu                     "file name: {FILE_NAME}",
164924fffdc8SGeorge Liu                     "FILE_NAME", i2cControllerWRAllowlistFile);
165084bf9be5SRichard Marian Thomaiyar                 return false;
165184bf9be5SRichard Marian Thomaiyar             }
165284bf9be5SRichard Marian Thomaiyar             const std::vector<uint8_t>& writeData =
165384bf9be5SRichard Marian Thomaiyar                 convertStringToData(filter[cmdStr].get<std::string>());
165484bf9be5SRichard Marian Thomaiyar             const std::vector<uint8_t>& writeDataMask =
165584bf9be5SRichard Marian Thomaiyar                 convertStringToData(filter[cmdMaskStr].get<std::string>());
165684bf9be5SRichard Marian Thomaiyar             if (writeDataMask.size() != writeData.size())
165784bf9be5SRichard Marian Thomaiyar             {
165824fffdc8SGeorge Liu                 lg2::error("I2C controller write read allowlist filter "
165984bf9be5SRichard Marian Thomaiyar                            "mismatch for command & mask size");
166084bf9be5SRichard Marian Thomaiyar                 return false;
166184bf9be5SRichard Marian Thomaiyar             }
166268d9d405SMatt Simmering             allowlist.push_back(
166384bf9be5SRichard Marian Thomaiyar                 {static_cast<uint8_t>(std::stoul(
166484bf9be5SRichard Marian Thomaiyar                      filter[busIdStr].get<std::string>(), nullptr, base_16)),
166584bf9be5SRichard Marian Thomaiyar                  static_cast<uint8_t>(
166668d9d405SMatt Simmering                      std::stoul(filter[targetAddrStr].get<std::string>(),
166784bf9be5SRichard Marian Thomaiyar                                 nullptr, base_16)),
166884bf9be5SRichard Marian Thomaiyar                  static_cast<uint8_t>(
166968d9d405SMatt Simmering                      std::stoul(filter[targetAddrMaskStr].get<std::string>(),
167084bf9be5SRichard Marian Thomaiyar                                 nullptr, base_16)),
167184bf9be5SRichard Marian Thomaiyar                  writeData, writeDataMask});
167284bf9be5SRichard Marian Thomaiyar         }
167368d9d405SMatt Simmering         if (allowlist.size() != filters.size())
167484bf9be5SRichard Marian Thomaiyar         {
167524fffdc8SGeorge Liu             lg2::error(
167668d9d405SMatt Simmering                 "I2C controller write read allowlist filter size mismatch");
167784bf9be5SRichard Marian Thomaiyar             return false;
167884bf9be5SRichard Marian Thomaiyar         }
167984bf9be5SRichard Marian Thomaiyar     }
1680a2ad2da8SPatrick Williams     catch (const std::exception& e)
168184bf9be5SRichard Marian Thomaiyar     {
168224fffdc8SGeorge Liu         lg2::error("I2C controller write read allowlist "
168324fffdc8SGeorge Liu                    "unexpected exception: {ERROR}",
168424fffdc8SGeorge Liu                    "ERROR", e);
168584bf9be5SRichard Marian Thomaiyar         return false;
168684bf9be5SRichard Marian Thomaiyar     }
168784bf9be5SRichard Marian Thomaiyar     return true;
168884bf9be5SRichard Marian Thomaiyar }
168984bf9be5SRichard Marian Thomaiyar 
isWriteDataAllowlisted(const std::vector<uint8_t> & data,const std::vector<uint8_t> & dataMask,const std::vector<uint8_t> & writeData)169068d9d405SMatt Simmering static inline bool isWriteDataAllowlisted(const std::vector<uint8_t>& data,
169184bf9be5SRichard Marian Thomaiyar                                           const std::vector<uint8_t>& dataMask,
169284bf9be5SRichard Marian Thomaiyar                                           const std::vector<uint8_t>& writeData)
169384bf9be5SRichard Marian Thomaiyar {
169484bf9be5SRichard Marian Thomaiyar     std::vector<uint8_t> processedDataBuf(data.size());
169584bf9be5SRichard Marian Thomaiyar     std::vector<uint8_t> processedReqBuf(dataMask.size());
169684bf9be5SRichard Marian Thomaiyar     std::transform(writeData.begin(), writeData.end(), dataMask.begin(),
169784bf9be5SRichard Marian Thomaiyar                    processedReqBuf.begin(), std::bit_or<uint8_t>());
169884bf9be5SRichard Marian Thomaiyar     std::transform(data.begin(), data.end(), dataMask.begin(),
169984bf9be5SRichard Marian Thomaiyar                    processedDataBuf.begin(), std::bit_or<uint8_t>());
170084bf9be5SRichard Marian Thomaiyar 
170184bf9be5SRichard Marian Thomaiyar     return (processedDataBuf == processedReqBuf);
170284bf9be5SRichard Marian Thomaiyar }
170384bf9be5SRichard Marian Thomaiyar 
isCmdAllowlisted(uint8_t busId,uint8_t targetAddr,std::vector<uint8_t> & writeData)170468d9d405SMatt Simmering static bool isCmdAllowlisted(uint8_t busId, uint8_t targetAddr,
170584bf9be5SRichard Marian Thomaiyar                              std::vector<uint8_t>& writeData)
170684bf9be5SRichard Marian Thomaiyar {
170768d9d405SMatt Simmering     std::vector<i2cControllerWRAllowlist>& allowList = getWRAllowlist();
170868d9d405SMatt Simmering     for (const auto& wlEntry : allowList)
170984bf9be5SRichard Marian Thomaiyar     {
171084bf9be5SRichard Marian Thomaiyar         if ((busId == wlEntry.busId) &&
171168d9d405SMatt Simmering             ((targetAddr | wlEntry.targetAddrMask) ==
171268d9d405SMatt Simmering              (wlEntry.targetAddr | wlEntry.targetAddrMask)))
171384bf9be5SRichard Marian Thomaiyar         {
171484bf9be5SRichard Marian Thomaiyar             const std::vector<uint8_t>& dataMask = wlEntry.dataMask;
171584bf9be5SRichard Marian Thomaiyar             // Skip as no-match, if requested write data is more than the
171684bf9be5SRichard Marian Thomaiyar             // write data mask size
171784bf9be5SRichard Marian Thomaiyar             if (writeData.size() > dataMask.size())
171884bf9be5SRichard Marian Thomaiyar             {
171984bf9be5SRichard Marian Thomaiyar                 continue;
172084bf9be5SRichard Marian Thomaiyar             }
172168d9d405SMatt Simmering             if (isWriteDataAllowlisted(wlEntry.data, dataMask, writeData))
172284bf9be5SRichard Marian Thomaiyar             {
172384bf9be5SRichard Marian Thomaiyar                 return true;
172484bf9be5SRichard Marian Thomaiyar             }
172584bf9be5SRichard Marian Thomaiyar         }
172684bf9be5SRichard Marian Thomaiyar     }
172784bf9be5SRichard Marian Thomaiyar     return false;
172884bf9be5SRichard Marian Thomaiyar }
1729bd0503a7SYong Li #else
populateI2CControllerWRAllowlist()173068d9d405SMatt Simmering static bool populateI2CControllerWRAllowlist()
1731bd0503a7SYong Li {
173224fffdc8SGeorge Liu     lg2::info("I2C_WHITELIST_CHECK is disabled, do not populate allowlist");
1733bd0503a7SYong Li     return true;
1734bd0503a7SYong Li }
1735bd0503a7SYong Li #endif // ENABLE_I2C_WHITELIST_CHECK
173684bf9be5SRichard Marian Thomaiyar 
173768d9d405SMatt Simmering /** @brief implements controller write read IPMI command which can be used for
173884bf9be5SRichard Marian Thomaiyar  * low-level I2C/SMBus write, read or write-read access
173984bf9be5SRichard Marian Thomaiyar  *  @param isPrivateBus -to indicate private bus usage
174084bf9be5SRichard Marian Thomaiyar  *  @param busId - bus id
174184bf9be5SRichard Marian Thomaiyar  *  @param channelNum - channel number
174284bf9be5SRichard Marian Thomaiyar  *  @param reserved - skip 1 bit
174368d9d405SMatt Simmering  *  @param targetAddr - target address
174484bf9be5SRichard Marian Thomaiyar  *  @param read count - number of bytes to be read
174584bf9be5SRichard Marian Thomaiyar  *  @param writeData - data to be written
174684bf9be5SRichard Marian Thomaiyar  *
174784bf9be5SRichard Marian Thomaiyar  *  @returns IPMI completion code plus response data
174884bf9be5SRichard Marian Thomaiyar  *   - readData - i2c response data
174984bf9be5SRichard Marian Thomaiyar  */
ipmiControllerWriteRead(bool isPrivateBus,uint3_t busId,uint4_t channelNum,bool reserved,uint7_t targetAddr,uint8_t readCount,std::vector<uint8_t> writeData)17501318a5edSPatrick Williams ipmi::RspType<std::vector<uint8_t>> ipmiControllerWriteRead(
17511318a5edSPatrick Williams     [[maybe_unused]] bool isPrivateBus, uint3_t busId,
17521318a5edSPatrick Williams     [[maybe_unused]] uint4_t channelNum, bool reserved, uint7_t targetAddr,
17531318a5edSPatrick Williams     uint8_t readCount, std::vector<uint8_t> writeData)
175484bf9be5SRichard Marian Thomaiyar {
1755c2af98beSJayaprakash Mutyala     if (reserved)
1756c2af98beSJayaprakash Mutyala     {
1757c2af98beSJayaprakash Mutyala         return ipmi::responseInvalidFieldRequest();
1758c2af98beSJayaprakash Mutyala     }
175984bf9be5SRichard Marian Thomaiyar     const size_t writeCount = writeData.size();
176084bf9be5SRichard Marian Thomaiyar     if (!readCount && !writeCount)
176184bf9be5SRichard Marian Thomaiyar     {
176224fffdc8SGeorge Liu         lg2::error("Controller write read command: Read & write count are 0");
176384bf9be5SRichard Marian Thomaiyar         return ipmi::responseInvalidFieldRequest();
176484bf9be5SRichard Marian Thomaiyar     }
1765bd0503a7SYong Li #ifdef ENABLE_I2C_WHITELIST_CHECK
176668d9d405SMatt Simmering     if (!isCmdAllowlisted(static_cast<uint8_t>(busId),
176768d9d405SMatt Simmering                           static_cast<uint8_t>(targetAddr), writeData))
176884bf9be5SRichard Marian Thomaiyar     {
176924fffdc8SGeorge Liu         lg2::error("Controller write read request blocked!, "
177024fffdc8SGeorge Liu                    "bus: {BUS}, addr: {ADDR}",
177124fffdc8SGeorge Liu                    "BUS", static_cast<uint8_t>(busId), "ADDR", lg2::hex,
177224fffdc8SGeorge Liu                    static_cast<uint8_t>(targetAddr));
177384bf9be5SRichard Marian Thomaiyar     }
1774bd0503a7SYong Li #endif // ENABLE_I2C_WHITELIST_CHECK
177584bf9be5SRichard Marian Thomaiyar     std::vector<uint8_t> readBuf(readCount);
17761318a5edSPatrick Williams     std::string i2cBus =
17771318a5edSPatrick Williams         "/dev/i2c-" + std::to_string(static_cast<uint8_t>(busId));
177884bf9be5SRichard Marian Thomaiyar 
177968d9d405SMatt Simmering     ipmi::Cc ret = ipmi::i2cWriteRead(i2cBus, static_cast<uint8_t>(targetAddr),
17807dc4ac02SYong Li                                       writeData, readBuf);
17817dc4ac02SYong Li     if (ret != ipmi::ccSuccess)
178284bf9be5SRichard Marian Thomaiyar     {
17837dc4ac02SYong Li         return ipmi::response(ret);
178484bf9be5SRichard Marian Thomaiyar     }
178584bf9be5SRichard Marian Thomaiyar     return ipmi::responseSuccess(readBuf);
178684bf9be5SRichard Marian Thomaiyar }
178784bf9be5SRichard Marian Thomaiyar 
registerNetFnAppFunctions()17885087b075SGeorge Liu void registerNetFnAppFunctions()
178998a23840SMatthew Barth {
179086a5082fSVernon Mauery     // <Get Device ID>
179186a5082fSVernon Mauery     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
179286a5082fSVernon Mauery                           ipmi::app::cmdGetDeviceId, ipmi::Privilege::User,
179386a5082fSVernon Mauery                           ipmiAppGetDeviceId);
179486a5082fSVernon Mauery 
17950573237fSTom     // <Get BT Interface Capabilities>
1796cc99ba43SVernon Mauery     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1797cc99ba43SVernon Mauery                           ipmi::app::cmdGetBtIfaceCapabilities,
1798cc99ba43SVernon Mauery                           ipmi::Privilege::User, ipmiAppGetBtCapabilities);
179998a23840SMatthew Barth 
18000573237fSTom     // <Reset Watchdog Timer>
180111df4f69SVernon Mauery     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
180211df4f69SVernon Mauery                           ipmi::app::cmdResetWatchdogTimer,
180311df4f69SVernon Mauery                           ipmi::Privilege::Operator, ipmiAppResetWatchdogTimer);
180498a23840SMatthew Barth 
1805f71444daSRajashekar Gade Reddy     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
18065a98ea63SAppaRao Puli                           ipmi::app::cmdGetSessionInfo, ipmi::Privilege::User,
18075a98ea63SAppaRao Puli                           ipmiAppGetSessionInfo);
1808f71444daSRajashekar Gade Reddy 
18090573237fSTom     // <Set Watchdog Timer>
1810cfae948bSDeepak Kumar Sahu     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1811cfae948bSDeepak Kumar Sahu                           ipmi::app::cmdSetWatchdogTimer,
1812cfae948bSDeepak Kumar Sahu                           ipmi::Privilege::Operator, ipmiSetWatchdogTimer);
181398a23840SMatthew Barth 
1814e7023926SRajashekar Gade Reddy     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1815e7023926SRajashekar Gade Reddy                           ipmi::app::cmdCloseSession, ipmi::Privilege::Callback,
1816e7023926SRajashekar Gade Reddy                           ipmiAppCloseSession);
1817e7023926SRajashekar Gade Reddy 
181873f44518SWilliam A. Kennington III     // <Get Watchdog Timer>
1819cfae948bSDeepak Kumar Sahu     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
18205a98ea63SAppaRao Puli                           ipmi::app::cmdGetWatchdogTimer, ipmi::Privilege::User,
18215a98ea63SAppaRao Puli                           ipmiGetWatchdogTimer);
182273f44518SWilliam A. Kennington III 
18230573237fSTom     // <Get Self Test Results>
1824b84a5282SVernon Mauery     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1825b84a5282SVernon Mauery                           ipmi::app::cmdGetSelfTestResults,
1826b84a5282SVernon Mauery                           ipmi::Privilege::User, ipmiAppGetSelfTestResults);
182741fa24a1SNan Li 
18280573237fSTom     // <Get Device GUID>
18291554132bSVernon Mauery     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
18301554132bSVernon Mauery                           ipmi::app::cmdGetDeviceGuid, ipmi::Privilege::User,
18311554132bSVernon Mauery                           ipmiAppGetDeviceGuid);
183298a23840SMatthew Barth 
18330573237fSTom     // <Set ACPI Power State>
1834520c1315SDeepak Kumar Sahu     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1835520c1315SDeepak Kumar Sahu                           ipmi::app::cmdSetAcpiPowerState,
1836520c1315SDeepak Kumar Sahu                           ipmi::Privilege::Admin, ipmiSetAcpiPowerState);
183718d77263SYong Li     // <Get ACPI Power State>
18384e6d2571SDeepak Kumar Sahu     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
18394e6d2571SDeepak Kumar Sahu                           ipmi::app::cmdGetAcpiPowerState,
18405a98ea63SAppaRao Puli                           ipmi::Privilege::User, ipmiGetAcpiPowerState);
184118d77263SYong Li 
184284bf9be5SRichard Marian Thomaiyar     // Note: For security reason, this command will be registered only when
184368d9d405SMatt Simmering     // there are proper I2C Controller write read allowlist
184468d9d405SMatt Simmering     if (populateI2CControllerWRAllowlist())
184584bf9be5SRichard Marian Thomaiyar     {
184668d9d405SMatt Simmering         // Note: For security reasons, registering controller write read as
184768d9d405SMatt Simmering         // admin privilege command, even though IPMI 2.0 specification allows it
184868d9d405SMatt Simmering         // as operator privilege.
184984bf9be5SRichard Marian Thomaiyar         ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
185084bf9be5SRichard Marian Thomaiyar                               ipmi::app::cmdMasterWriteRead,
185168d9d405SMatt Simmering                               ipmi::Privilege::Admin, ipmiControllerWriteRead);
185284bf9be5SRichard Marian Thomaiyar     }
185384bf9be5SRichard Marian Thomaiyar 
18545e007a5dSMarri Devender Rao     // <Get System GUID Command>
1855b90a5328SVernon Mauery     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1856b90a5328SVernon Mauery                           ipmi::app::cmdGetSystemGuid, ipmi::Privilege::User,
1857b90a5328SVernon Mauery                           ipmiAppGetSystemGuid);
18587cbe2286STom Joseph 
18597cbe2286STom Joseph     // <Get Channel Cipher Suites Command>
18605c3b72c6SAyushi Smriti     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
18615c3b72c6SAyushi Smriti                           ipmi::app::cmdGetChannelCipherSuites,
186279b4eeaaSVernon Mauery                           ipmi::Privilege::None, getChannelCipherSuites);
1863d2a57decSVernon Mauery 
1864f542e8b0SXo Wang     // <Get System Info Command>
186598b43babSJia, chunhui     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
186698b43babSJia, chunhui                           ipmi::app::cmdGetSystemInfoParameters,
186798b43babSJia, chunhui                           ipmi::Privilege::User, ipmiAppGetSystemInfo);
1868449f2166SJia, chunhui     // <Set System Info Command>
1869449f2166SJia, chunhui     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
1870449f2166SJia, chunhui                           ipmi::app::cmdSetSystemInfoParameters,
1871449f2166SJia, chunhui                           ipmi::Privilege::Admin, ipmiAppSetSystemInfo);
187298a23840SMatthew Barth     return;
187398a23840SMatthew Barth }
1874