1f8da32adSTom Joseph #include "guid.hpp"
2f8da32adSTom Joseph
34f09eaeeSWilliam A. Kennington III #include <ipmid/api.h>
49e801a2bSVernon Mauery
594b0d134SXie Ning #include <ipmid/utils.hpp>
694b0d134SXie Ning #include <phosphor-logging/elog-errors.hpp>
77b7f25f7SGeorge Liu #include <phosphor-logging/lg2.hpp>
894b0d134SXie Ning #include <xyz/openbmc_project/Common/error.hpp>
9bc8958feSGeorge Liu
10f8da32adSTom Joseph #include <sstream>
11f8da32adSTom Joseph #include <string>
12f8da32adSTom Joseph
13fc37e59eSVernon Mauery using namespace phosphor::logging;
1494b0d134SXie Ning using namespace sdbusplus::xyz::openbmc_project::Common::Error;
15fc37e59eSVernon Mauery
1636e3c539SVernon Mauery static std::optional<command::Guid> guid;
1783029cb8STom Joseph
18f8da32adSTom Joseph namespace command
19f8da32adSTom Joseph {
20f8da32adSTom Joseph
2183029cb8STom Joseph std::unique_ptr<sdbusplus::bus::match_t> matchPtr(nullptr);
2283029cb8STom Joseph
2394b0d134SXie Ning static constexpr auto propInterface = "xyz.openbmc_project.Common.UUID";
2494b0d134SXie Ning static constexpr auto uuidProperty = "UUID";
2536e3c539SVernon Mauery static constexpr auto subtreePath = "/xyz/openbmc_project/inventory";
2694b0d134SXie Ning
rfcToGuid(std::string rfc4122,Guid & uuid)2794b0d134SXie Ning static void rfcToGuid(std::string rfc4122, Guid& uuid)
2894b0d134SXie Ning {
2994b0d134SXie Ning using Argument = xyz::openbmc_project::Common::InvalidArgument;
3094b0d134SXie Ning // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
3194b0d134SXie Ning // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte
3294b0d134SXie Ning // order
3394b0d134SXie Ning // Ex: 0x2332fc2c40e66298e511f2782395a361
3494b0d134SXie Ning constexpr size_t uuidHexLength = (2 * BMC_GUID_LEN);
3594b0d134SXie Ning constexpr size_t uuidRfc4122Length = (uuidHexLength + 4);
3694b0d134SXie Ning
3794b0d134SXie Ning if (rfc4122.size() == uuidRfc4122Length)
3894b0d134SXie Ning {
3994b0d134SXie Ning rfc4122.erase(std::remove(rfc4122.begin(), rfc4122.end(), '-'),
4094b0d134SXie Ning rfc4122.end());
4194b0d134SXie Ning }
4294b0d134SXie Ning if (rfc4122.size() != uuidHexLength)
4394b0d134SXie Ning {
4494b0d134SXie Ning elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"),
4594b0d134SXie Ning Argument::ARGUMENT_VALUE(rfc4122.c_str()));
4694b0d134SXie Ning }
4794b0d134SXie Ning for (size_t ind = 0; ind < uuidHexLength; ind += 2)
4894b0d134SXie Ning {
4994b0d134SXie Ning long b;
5094b0d134SXie Ning try
5194b0d134SXie Ning {
5294b0d134SXie Ning b = std::stoul(rfc4122.substr(ind, 2), nullptr, 16);
5394b0d134SXie Ning }
5494b0d134SXie Ning catch (const std::exception& e)
5594b0d134SXie Ning {
5694b0d134SXie Ning elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"),
5794b0d134SXie Ning Argument::ARGUMENT_VALUE(rfc4122.c_str()));
5894b0d134SXie Ning }
5994b0d134SXie Ning
6094b0d134SXie Ning uuid[BMC_GUID_LEN - (ind / 2) - 1] = static_cast<uint8_t>(b);
6194b0d134SXie Ning }
6294b0d134SXie Ning return;
6394b0d134SXie Ning }
6483029cb8STom Joseph
6536e3c539SVernon Mauery // Canned System GUID for when the Chassis DBUS object is not populated
6636e3c539SVernon Mauery static constexpr Guid fakeGuid = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
6736e3c539SVernon Mauery 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
6836e3c539SVernon Mauery 0x0D, 0x0E, 0x0F, 0x10};
getSystemGUID()6936e3c539SVernon Mauery const Guid& getSystemGUID()
70f8da32adSTom Joseph {
7136e3c539SVernon Mauery if (guid.has_value())
7236e3c539SVernon Mauery {
7336e3c539SVernon Mauery return guid.value();
7436e3c539SVernon Mauery }
75f8da32adSTom Joseph
7694b0d134SXie Ning sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
77f8da32adSTom Joseph
7894b0d134SXie Ning ipmi::Value propValue;
7994b0d134SXie Ning try
80f8da32adSTom Joseph {
81*8425624aSPatrick Williams const auto& [objPath, service] =
82*8425624aSPatrick Williams ipmi::getDbusObject(bus, propInterface, subtreePath);
8394b0d134SXie Ning // Read UUID property value from bmcObject
8494b0d134SXie Ning // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
8536e3c539SVernon Mauery propValue = ipmi::getDbusProperty(bus, service, objPath, propInterface,
8694b0d134SXie Ning uuidProperty);
8794b0d134SXie Ning }
8894b0d134SXie Ning catch (const sdbusplus::exception_t& e)
89f8da32adSTom Joseph {
9094b0d134SXie Ning lg2::error("Failed in reading BMC UUID property: {ERROR}", "ERROR", e);
9136e3c539SVernon Mauery return fakeGuid;
92f8da32adSTom Joseph }
93f8da32adSTom Joseph
9494b0d134SXie Ning std::string rfc4122Uuid = std::get<std::string>(propValue);
9594b0d134SXie Ning try
96f8da32adSTom Joseph {
9794b0d134SXie Ning // convert to IPMI format
9836e3c539SVernon Mauery Guid tmpGuid{};
9936e3c539SVernon Mauery rfcToGuid(rfc4122Uuid, tmpGuid);
10036e3c539SVernon Mauery guid = tmpGuid;
101f8da32adSTom Joseph }
10294b0d134SXie Ning catch (const InvalidArgument& e)
103f8da32adSTom Joseph {
10494b0d134SXie Ning lg2::error("Failed in parsing BMC UUID property: {VALUE}", "VALUE",
10594b0d134SXie Ning rfc4122Uuid.c_str());
10636e3c539SVernon Mauery return fakeGuid;
107f8da32adSTom Joseph }
10836e3c539SVernon Mauery return guid.value();
109f8da32adSTom Joseph }
110f8da32adSTom Joseph
registerGUIDChangeCallback()11183029cb8STom Joseph void registerGUIDChangeCallback()
11283029cb8STom Joseph {
11383029cb8STom Joseph if (matchPtr == nullptr)
11483029cb8STom Joseph {
11583029cb8STom Joseph using namespace sdbusplus::bus::match::rules;
1160a59062cSPatrick Williams sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
11783029cb8STom Joseph
11836e3c539SVernon Mauery try
11936e3c539SVernon Mauery {
12083029cb8STom Joseph matchPtr = std::make_unique<sdbusplus::bus::match_t>(
12136e3c539SVernon Mauery bus, propertiesChangedNamespace(subtreePath, propInterface),
12236e3c539SVernon Mauery [](sdbusplus::message_t& m) {
12336e3c539SVernon Mauery try
12436e3c539SVernon Mauery {
12536e3c539SVernon Mauery std::string iface{};
12636e3c539SVernon Mauery std::map<std::string, ipmi::Value> pdict{};
12736e3c539SVernon Mauery m.read(iface, pdict);
12836e3c539SVernon Mauery if (iface != propInterface)
12936e3c539SVernon Mauery {
13036e3c539SVernon Mauery return;
13136e3c539SVernon Mauery }
13236e3c539SVernon Mauery auto guidStr = std::get<std::string>(pdict.at("UUID"));
13336e3c539SVernon Mauery Guid tmpGuid{};
13436e3c539SVernon Mauery rfcToGuid(guidStr, tmpGuid);
13536e3c539SVernon Mauery guid = tmpGuid;
13636e3c539SVernon Mauery }
13736e3c539SVernon Mauery catch (const std::exception& e)
13836e3c539SVernon Mauery {
13936e3c539SVernon Mauery // signal contained invalid guid; ignore it
14036e3c539SVernon Mauery lg2::error(
14136e3c539SVernon Mauery "Failed to parse propertiesChanged signal: {ERROR}",
14236e3c539SVernon Mauery "ERROR", e);
14336e3c539SVernon Mauery }
14436e3c539SVernon Mauery });
14536e3c539SVernon Mauery }
14636e3c539SVernon Mauery catch (const std::exception& e)
14736e3c539SVernon Mauery {
14836e3c539SVernon Mauery lg2::error("Failed to create dbus match: {ERROR}", "ERROR", e);
14936e3c539SVernon Mauery }
15083029cb8STom Joseph }
15183029cb8STom Joseph }
15283029cb8STom Joseph
153f8da32adSTom Joseph } // namespace command
154