Load IPMI provider libraries into net-ipmid

The logic to scan /usr/lib/net-ipmid for shared libraries
and load them and the callback function to register commands
to command table.

Change-Id: Ib09cce5a9b418171822208d1d7b322e4b1c8b2b9
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/provider_registration.cpp b/provider_registration.cpp
new file mode 100644
index 0000000..aaa397c
--- /dev/null
+++ b/provider_registration.cpp
@@ -0,0 +1,103 @@
+#include <dirent.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <iostream>
+
+#include <host-ipmid/ipmid-api.h>
+#include "command_table.hpp"
+#include "main.hpp"
+#include "provider_registration.hpp"
+
+namespace provider
+{
+
+int handler_select(const struct dirent* entry)
+{
+    // Check for versioned libraries .so.*
+    if (strstr(entry->d_name, PROVIDER_SONAME_EXTN))
+    {
+        return 1;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+void registerCallbackHandlers(const char* providerLibPath)
+{
+    if (providerLibPath == NULL)
+    {
+        std::cerr << "Path not provided for registering IPMI provider libraries"
+                  << "\n";
+        return;
+    }
+
+    struct dirent** handlerList = nullptr;
+    std::string handlerPath(providerLibPath);
+
+    auto numLibs = scandir(providerLibPath, &handlerList, handler_select,
+                           alphasort);
+    if (numLibs < 0)
+    {
+        return;
+    }
+
+    // dlopen each IPMI provider shared library
+    while (numLibs--)
+    {
+        handlerPath = providerLibPath;
+        handlerPath += handlerList[numLibs]->d_name;
+        std::cout << "Registering handler: " << handlerPath << "\n";
+
+        auto lib_handler = dlopen(handlerPath.c_str(), RTLD_NOW);
+
+        if (lib_handler == NULL)
+        {
+            std::cerr << "Error opening " << handlerPath << dlerror() << "\n";
+        }
+        free(handlerList[numLibs]);
+    }
+
+    free(handlerList);
+}
+
+} // namespace provider
+
+/*
+ * @brief Method that gets called from IPMI provider shared libraries to get
+ *        the command handlers registered.
+ *
+ * When the IPMI provider shared library is loaded, the dynamic loader program
+ * looks for special section(.ctors on ELF) which contains references to the
+ * functions marked with the constructor attributes. This function is invoked
+ * in such manner.
+ *
+ * @param[in] netfn - Network Function code
+ * @param[in] cmd - Command
+ * @param[in] context - User specific data
+ * @param[in] handler - The callback routine for the command
+ * @param[in] priv - IPMI Command Prvilege
+ */
+void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                            ipmi_context_t context,
+                            ipmid_callback_t handler, ipmi_cmd_privilege priv)
+{
+    uint16_t netFn = netfn << 10;
+
+    // The payload type of IPMI commands provided by the shared libraries
+    // is IPMI
+    command::CommandID command =
+    {
+        ((static_cast<uint32_t>(message::PayloadType::IPMI)) << 16) |
+        netFn | cmd
+    };
+
+    std::get<command::Table&>(singletonPool).registerCommand(command,
+            std::make_unique<command::ProviderIpmidEntry>
+            (command, handler, static_cast<session::Privilege>(priv)));
+}
+
+