1 #include "guid.hpp" 2 3 #include <ipmid/api.h> 4 5 #include <ipmid/utils.hpp> 6 #include <phosphor-logging/elog-errors.hpp> 7 #include <phosphor-logging/lg2.hpp> 8 #include <xyz/openbmc_project/Common/error.hpp> 9 10 #include <sstream> 11 #include <string> 12 13 using namespace phosphor::logging; 14 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 15 16 static std::optional<command::Guid> guid; 17 18 namespace command 19 { 20 21 std::unique_ptr<sdbusplus::bus::match_t> matchPtr(nullptr); 22 23 static constexpr auto propInterface = "xyz.openbmc_project.Common.UUID"; 24 static constexpr auto uuidProperty = "UUID"; 25 static constexpr auto subtreePath = "/xyz/openbmc_project/inventory"; 26 27 static void rfcToGuid(std::string rfc4122, Guid& uuid) 28 { 29 using Argument = xyz::openbmc_project::Common::InvalidArgument; 30 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 31 // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte 32 // order 33 // Ex: 0x2332fc2c40e66298e511f2782395a361 34 constexpr size_t uuidHexLength = (2 * BMC_GUID_LEN); 35 constexpr size_t uuidRfc4122Length = (uuidHexLength + 4); 36 37 if (rfc4122.size() == uuidRfc4122Length) 38 { 39 rfc4122.erase(std::remove(rfc4122.begin(), rfc4122.end(), '-'), 40 rfc4122.end()); 41 } 42 if (rfc4122.size() != uuidHexLength) 43 { 44 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"), 45 Argument::ARGUMENT_VALUE(rfc4122.c_str())); 46 } 47 for (size_t ind = 0; ind < uuidHexLength; ind += 2) 48 { 49 long b; 50 try 51 { 52 b = std::stoul(rfc4122.substr(ind, 2), nullptr, 16); 53 } 54 catch (const std::exception& e) 55 { 56 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"), 57 Argument::ARGUMENT_VALUE(rfc4122.c_str())); 58 } 59 60 uuid[BMC_GUID_LEN - (ind / 2) - 1] = static_cast<uint8_t>(b); 61 } 62 return; 63 } 64 65 // Canned System GUID for when the Chassis DBUS object is not populated 66 static constexpr Guid fakeGuid = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 67 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 68 0x0D, 0x0E, 0x0F, 0x10}; 69 const Guid& getSystemGUID() 70 { 71 if (guid.has_value()) 72 { 73 return guid.value(); 74 } 75 76 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()}; 77 78 ipmi::Value propValue; 79 try 80 { 81 const auto& [objPath, service] = ipmi::getDbusObject(bus, propInterface, 82 subtreePath); 83 // Read UUID property value from bmcObject 84 // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 85 propValue = ipmi::getDbusProperty(bus, service, objPath, propInterface, 86 uuidProperty); 87 } 88 catch (const sdbusplus::exception_t& e) 89 { 90 lg2::error("Failed in reading BMC UUID property: {ERROR}", "ERROR", e); 91 return fakeGuid; 92 } 93 94 std::string rfc4122Uuid = std::get<std::string>(propValue); 95 try 96 { 97 // convert to IPMI format 98 Guid tmpGuid{}; 99 rfcToGuid(rfc4122Uuid, tmpGuid); 100 guid = tmpGuid; 101 } 102 catch (const InvalidArgument& e) 103 { 104 lg2::error("Failed in parsing BMC UUID property: {VALUE}", "VALUE", 105 rfc4122Uuid.c_str()); 106 return fakeGuid; 107 } 108 return guid.value(); 109 } 110 111 void registerGUIDChangeCallback() 112 { 113 if (matchPtr == nullptr) 114 { 115 using namespace sdbusplus::bus::match::rules; 116 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()}; 117 118 try 119 { 120 matchPtr = std::make_unique<sdbusplus::bus::match_t>( 121 bus, propertiesChangedNamespace(subtreePath, propInterface), 122 [](sdbusplus::message_t& m) { 123 try 124 { 125 std::string iface{}; 126 std::map<std::string, ipmi::Value> pdict{}; 127 m.read(iface, pdict); 128 if (iface != propInterface) 129 { 130 return; 131 } 132 auto guidStr = std::get<std::string>(pdict.at("UUID")); 133 Guid tmpGuid{}; 134 rfcToGuid(guidStr, tmpGuid); 135 guid = tmpGuid; 136 } 137 catch (const std::exception& e) 138 { 139 // signal contained invalid guid; ignore it 140 lg2::error( 141 "Failed to parse propertiesChanged signal: {ERROR}", 142 "ERROR", e); 143 } 144 }); 145 } 146 catch (const std::exception& e) 147 { 148 lg2::error("Failed to create dbus match: {ERROR}", "ERROR", e); 149 } 150 } 151 } 152 153 } // namespace command 154