xref: /openbmc/phosphor-net-ipmid/command/guid.cpp (revision 94b0d134c0b8f0230e7d74c8ac34ebeea5ba91e1)
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