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