fw-update: Firmware discovery of MCTP endpoints

Tested:

a) Verified MCTP endpoints are discovered by PLDM and fetching the firmware
   inventory commands.
b) PLDM firmware update successful after uploading the package, which depends
   on the firmware inventory commands.
c) Verified MCTP endpoints are discovered irrespective of the startup order
   with the MCTP control application.

Signed-off-by: Tom Joseph <rushtotom@gmail.com>
Change-Id: I7ee9aed40433a8e5a4ebb8e61f917ec82dde9c35
diff --git a/requester/mctp_endpoint_discovery.cpp b/requester/mctp_endpoint_discovery.cpp
new file mode 100644
index 0000000..b95935f
--- /dev/null
+++ b/requester/mctp_endpoint_discovery.cpp
@@ -0,0 +1,106 @@
+#include "mctp_endpoint_discovery.hpp"
+
+#include "libpldm/requester/pldm.h"
+
+#include "common/types.hpp"
+#include "common/utils.hpp"
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <string_view>
+#include <vector>
+
+namespace pldm
+{
+
+MctpDiscovery::MctpDiscovery(sdbusplus::bus::bus& bus,
+                             fw_update::Manager* fwManager) :
+    bus(bus),
+    fwManager(fwManager),
+    mctpEndpointSignal(bus,
+                       sdbusplus::bus::match::rules::interfacesAdded(
+                           "/xyz/openbmc_project/mctp"),
+                       std::bind_front(&MctpDiscovery::dicoverEndpoints, this))
+{
+    dbus::ObjectValueTree objects;
+
+    try
+    {
+        auto method = bus.new_method_call(
+            "xyz.openbmc_project.MCTP.Control", "/xyz/openbmc_project/mctp",
+            "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+        auto reply = bus.call(method);
+        reply.read(objects);
+    }
+    catch (const std::exception& e)
+    {
+        return;
+    }
+
+    std::vector<mctp_eid_t> eids;
+
+    for (const auto& [objectPath, interfaces] : objects)
+    {
+        for (const auto& [intfName, properties] : interfaces)
+        {
+            if (intfName == mctpEndpointIntfName)
+            {
+                if (properties.contains("EID") &&
+                    properties.contains("SupportedMessageTypes"))
+                {
+                    auto eid = std::get<size_t>(properties.at("EID"));
+                    auto types = std::get<std::vector<uint8_t>>(
+                        properties.at("SupportedMessageTypes"));
+                    if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
+                        types.end())
+                    {
+                        eids.emplace_back(eid);
+                    }
+                }
+            }
+        }
+    }
+
+    if (eids.size() && fwManager)
+    {
+        fwManager->handleMCTPEndpoints(eids);
+    }
+}
+
+void MctpDiscovery::dicoverEndpoints(sdbusplus::message::message& msg)
+{
+    constexpr std::string_view mctpEndpointIntfName{
+        "xyz.openbmc_project.MCTP.Endpoint"};
+    std::vector<mctp_eid_t> eids;
+
+    sdbusplus::message::object_path objPath;
+    std::map<std::string, std::map<std::string, dbus::Value>> interfaces;
+    msg.read(objPath, interfaces);
+
+    for (const auto& [intfName, properties] : interfaces)
+    {
+        if (intfName == mctpEndpointIntfName)
+        {
+            if (properties.contains("EID") &&
+                properties.contains("SupportedMessageTypes"))
+            {
+                auto eid = std::get<size_t>(properties.at("EID"));
+                auto types = std::get<std::vector<uint8_t>>(
+                    properties.at("SupportedMessageTypes"));
+                if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
+                    types.end())
+                {
+                    eids.emplace_back(eid);
+                }
+            }
+        }
+    }
+
+    if (eids.size() && fwManager)
+    {
+        fwManager->handleMCTPEndpoints(eids);
+    }
+}
+
+} // namespace pldm
\ No newline at end of file