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