1f8da32adSTom Joseph #include "guid.hpp" 2f8da32adSTom Joseph 34f09eaeeSWilliam A. Kennington III #include <ipmid/api.h> 49e801a2bSVernon Mauery #include <mapper.h> 59e801a2bSVernon Mauery 694b0d134SXie Ning #include <ipmid/utils.hpp> 794b0d134SXie Ning #include <phosphor-logging/elog-errors.hpp> 87b7f25f7SGeorge Liu #include <phosphor-logging/lg2.hpp> 994b0d134SXie Ning #include <xyz/openbmc_project/Common/error.hpp> 10bc8958feSGeorge Liu 11f8da32adSTom Joseph #include <sstream> 12f8da32adSTom Joseph #include <string> 13f8da32adSTom Joseph 14fc37e59eSVernon Mauery using namespace phosphor::logging; 1594b0d134SXie Ning using namespace sdbusplus::xyz::openbmc_project::Common::Error; 16fc37e59eSVernon Mauery 17*36e3c539SVernon Mauery static std::optional<command::Guid> guid; 1883029cb8STom Joseph 19f8da32adSTom Joseph namespace command 20f8da32adSTom Joseph { 21f8da32adSTom Joseph 2283029cb8STom Joseph std::unique_ptr<sdbusplus::bus::match_t> matchPtr(nullptr); 2383029cb8STom Joseph 2494b0d134SXie Ning static constexpr auto propInterface = "xyz.openbmc_project.Common.UUID"; 2594b0d134SXie Ning static constexpr auto uuidProperty = "UUID"; 26*36e3c539SVernon Mauery static constexpr auto subtreePath = "/xyz/openbmc_project/inventory"; 2794b0d134SXie Ning 2894b0d134SXie Ning static void rfcToGuid(std::string rfc4122, Guid& uuid) 2994b0d134SXie Ning { 3094b0d134SXie Ning using Argument = xyz::openbmc_project::Common::InvalidArgument; 3194b0d134SXie Ning // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 3294b0d134SXie Ning // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte 3394b0d134SXie Ning // order 3494b0d134SXie Ning // Ex: 0x2332fc2c40e66298e511f2782395a361 3594b0d134SXie Ning constexpr size_t uuidHexLength = (2 * BMC_GUID_LEN); 3694b0d134SXie Ning constexpr size_t uuidRfc4122Length = (uuidHexLength + 4); 3794b0d134SXie Ning 3894b0d134SXie Ning if (rfc4122.size() == uuidRfc4122Length) 3994b0d134SXie Ning { 4094b0d134SXie Ning rfc4122.erase(std::remove(rfc4122.begin(), rfc4122.end(), '-'), 4194b0d134SXie Ning rfc4122.end()); 4294b0d134SXie Ning } 4394b0d134SXie Ning if (rfc4122.size() != uuidHexLength) 4494b0d134SXie Ning { 4594b0d134SXie Ning elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"), 4694b0d134SXie Ning Argument::ARGUMENT_VALUE(rfc4122.c_str())); 4794b0d134SXie Ning } 4894b0d134SXie Ning for (size_t ind = 0; ind < uuidHexLength; ind += 2) 4994b0d134SXie Ning { 5094b0d134SXie Ning long b; 5194b0d134SXie Ning try 5294b0d134SXie Ning { 5394b0d134SXie Ning b = std::stoul(rfc4122.substr(ind, 2), nullptr, 16); 5494b0d134SXie Ning } 5594b0d134SXie Ning catch (const std::exception& e) 5694b0d134SXie Ning { 5794b0d134SXie Ning elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"), 5894b0d134SXie Ning Argument::ARGUMENT_VALUE(rfc4122.c_str())); 5994b0d134SXie Ning } 6094b0d134SXie Ning 6194b0d134SXie Ning uuid[BMC_GUID_LEN - (ind / 2) - 1] = static_cast<uint8_t>(b); 6294b0d134SXie Ning } 6394b0d134SXie Ning return; 6494b0d134SXie Ning } 6583029cb8STom Joseph 66*36e3c539SVernon Mauery // Canned System GUID for when the Chassis DBUS object is not populated 67*36e3c539SVernon Mauery static constexpr Guid fakeGuid = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 68*36e3c539SVernon Mauery 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 69*36e3c539SVernon Mauery 0x0D, 0x0E, 0x0F, 0x10}; 70*36e3c539SVernon Mauery const Guid& getSystemGUID() 71f8da32adSTom Joseph { 72*36e3c539SVernon Mauery if (guid.has_value()) 73*36e3c539SVernon Mauery { 74*36e3c539SVernon Mauery return guid.value(); 75*36e3c539SVernon Mauery } 76f8da32adSTom Joseph 7794b0d134SXie Ning sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()}; 78f8da32adSTom Joseph 7994b0d134SXie Ning ipmi::Value propValue; 8094b0d134SXie Ning try 81f8da32adSTom Joseph { 82*36e3c539SVernon Mauery const auto& [objPath, service] = ipmi::getDbusObject(bus, propInterface, 83*36e3c539SVernon Mauery subtreePath); 8494b0d134SXie Ning // Read UUID property value from bmcObject 8594b0d134SXie Ning // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 86*36e3c539SVernon Mauery propValue = ipmi::getDbusProperty(bus, service, objPath, propInterface, 8794b0d134SXie Ning uuidProperty); 8894b0d134SXie Ning } 8994b0d134SXie Ning catch (const sdbusplus::exception_t& e) 90f8da32adSTom Joseph { 9194b0d134SXie Ning lg2::error("Failed in reading BMC UUID property: {ERROR}", "ERROR", e); 92*36e3c539SVernon Mauery return fakeGuid; 93f8da32adSTom Joseph } 94f8da32adSTom Joseph 9594b0d134SXie Ning std::string rfc4122Uuid = std::get<std::string>(propValue); 9694b0d134SXie Ning try 97f8da32adSTom Joseph { 9894b0d134SXie Ning // convert to IPMI format 99*36e3c539SVernon Mauery Guid tmpGuid{}; 100*36e3c539SVernon Mauery rfcToGuid(rfc4122Uuid, tmpGuid); 101*36e3c539SVernon Mauery guid = tmpGuid; 102f8da32adSTom Joseph } 10394b0d134SXie Ning catch (const InvalidArgument& e) 104f8da32adSTom Joseph { 10594b0d134SXie Ning lg2::error("Failed in parsing BMC UUID property: {VALUE}", "VALUE", 10694b0d134SXie Ning rfc4122Uuid.c_str()); 107*36e3c539SVernon Mauery return fakeGuid; 108f8da32adSTom Joseph } 109*36e3c539SVernon Mauery return guid.value(); 110f8da32adSTom Joseph } 111f8da32adSTom Joseph 11283029cb8STom Joseph void registerGUIDChangeCallback() 11383029cb8STom Joseph { 11483029cb8STom Joseph if (matchPtr == nullptr) 11583029cb8STom Joseph { 11683029cb8STom Joseph using namespace sdbusplus::bus::match::rules; 1170a59062cSPatrick Williams sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()}; 11883029cb8STom Joseph 119*36e3c539SVernon Mauery try 120*36e3c539SVernon Mauery { 12183029cb8STom Joseph matchPtr = std::make_unique<sdbusplus::bus::match_t>( 122*36e3c539SVernon Mauery bus, propertiesChangedNamespace(subtreePath, propInterface), 123*36e3c539SVernon Mauery [](sdbusplus::message_t& m) { 124*36e3c539SVernon Mauery try 125*36e3c539SVernon Mauery { 126*36e3c539SVernon Mauery std::string iface{}; 127*36e3c539SVernon Mauery std::map<std::string, ipmi::Value> pdict{}; 128*36e3c539SVernon Mauery m.read(iface, pdict); 129*36e3c539SVernon Mauery if (iface != propInterface) 130*36e3c539SVernon Mauery { 131*36e3c539SVernon Mauery return; 132*36e3c539SVernon Mauery } 133*36e3c539SVernon Mauery auto guidStr = std::get<std::string>(pdict.at("UUID")); 134*36e3c539SVernon Mauery Guid tmpGuid{}; 135*36e3c539SVernon Mauery rfcToGuid(guidStr, tmpGuid); 136*36e3c539SVernon Mauery guid = tmpGuid; 137*36e3c539SVernon Mauery } 138*36e3c539SVernon Mauery catch (const std::exception& e) 139*36e3c539SVernon Mauery { 140*36e3c539SVernon Mauery // signal contained invalid guid; ignore it 141*36e3c539SVernon Mauery lg2::error( 142*36e3c539SVernon Mauery "Failed to parse propertiesChanged signal: {ERROR}", 143*36e3c539SVernon Mauery "ERROR", e); 144*36e3c539SVernon Mauery } 145*36e3c539SVernon Mauery }); 146*36e3c539SVernon Mauery } 147*36e3c539SVernon Mauery catch (const std::exception& e) 148*36e3c539SVernon Mauery { 149*36e3c539SVernon Mauery lg2::error("Failed to create dbus match: {ERROR}", "ERROR", e); 150*36e3c539SVernon Mauery } 15183029cb8STom Joseph } 15283029cb8STom Joseph } 15383029cb8STom Joseph 154f8da32adSTom Joseph } // namespace command 155