netipmid: Update netipmid to use ipmid as the main queue

All ipmi processing is now done in the main ipmi queue
(phosphor-host-ipmid) and messages are passed via dbus. This removes the
handler registration for providers and just passes the message along to
the main queue instead of executing the provider in-situ. This makes the
net-ipmid more like the bt-bridge or kcs-bridge that are simple channel
handlers that move messages from a medium to the queue.

Change-Id: Icc9d580fd5546505c95acf0bea47c70e09809b7d
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/Makefile.am b/Makefile.am
index 392b820..f8b2160 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -41,8 +41,6 @@
 	main.cpp \
 	integrity_algo.hpp \
 	integrity_algo.cpp \
-	provider_registration.hpp \
-	provider_registration.cpp \
 	crypt_algo.hpp \
 	crypt_algo.cpp \
 	sol/console_buffer.hpp \
@@ -71,10 +69,8 @@
 	$(PHOSPHOR_LOGGING_LIBS) \
 	$(PHOSPHOR_DBUS_INTERFACES_LIBS) \
 	$(LIBIPMID_LIBS) \
-	$(LIBADD_DLOPEN) \
 	-lchannellayer \
-	-luserlayer \
-	-export-dynamic
+	-luserlayer
 
 netipmid_CXXFLAGS = \
 	-flto \
diff --git a/command_table.cpp b/command_table.cpp
index d0ef173..e911bc6 100644
--- a/command_table.cpp
+++ b/command_table.cpp
@@ -6,12 +6,23 @@
 #include "sessions_manager.hpp"
 
 #include <iomanip>
+#include <main.hpp>
 #include <phosphor-logging/elog-errors.hpp>
 #include <phosphor-logging/log.hpp>
+#include <user_channel/user_layer.hpp>
 #include <xyz/openbmc_project/Common/error.hpp>
 
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
 using namespace phosphor::logging;
 
+namespace ipmi
+{
+using Value = sdbusplus::message::variant<bool, uint8_t, int16_t, uint16_t,
+                                          int32_t, uint32_t, int64_t, uint64_t,
+                                          double, std::string>;
+
+} // namespace ipmi
+
 namespace command
 {
 
@@ -23,8 +34,7 @@
     {
         log<level::DEBUG>(
             "Already Registered",
-            phosphor::logging::entry("SKIPPED_ENTRY=0x%x",
-                                     uint32_t(inCommand.command)));
+            phosphor::logging::entry("SKIPPED_ENTRY=0x%x", inCommand.command));
         return;
     }
 
@@ -43,8 +53,52 @@
 
     if (iterator == commandTable.end())
     {
-        response.resize(1);
-        response[0] = IPMI_CC_INVALID;
+        CommandID command(inCommand);
+
+        auto bus = getSdBus();
+        // forward the request onto the main ipmi queue
+        auto method = bus->new_method_call(
+            "xyz.openbmc_project.Ipmi.Host", "/xyz/openbmc_project/Ipmi",
+            "xyz.openbmc_project.Ipmi.Server", "execute");
+        uint8_t lun = command.lun();
+        uint8_t netFn = command.netFn();
+        uint8_t cmd = command.cmd();
+        std::shared_ptr<session::Session> session =
+            std::get<session::Manager&>(singletonPool)
+                .getSession(handler.sessionID);
+        std::map<std::string, ipmi::Value> options = {
+            {"userId", ipmi::Value(ipmi::ipmiUserGetUserId(session->userName))},
+            {"privilege", ipmi::Value(static_cast<int>(session->curPrivLevel))},
+        };
+        method.append(netFn, lun, cmd, commandData, options);
+        using IpmiDbusRspType = std::tuple<uint8_t, uint8_t, uint8_t, uint8_t,
+                                           std::vector<uint8_t>>;
+        IpmiDbusRspType rspTuple;
+        try
+        {
+            auto reply = bus->call(method);
+            reply.read(rspTuple);
+        }
+        catch (const sdbusplus::exception::SdBusError& e)
+        {
+            response.push_back(IPMI_CC_UNSPECIFIED_ERROR);
+            log<level::ERR>("Error sending command to ipmi queue");
+            elog<InternalFailure>();
+        }
+        auto& [rnetFn, rlun, rcmd, cc, responseData] = rspTuple;
+        if (uint8_t(netFn + 1) != rnetFn || rlun != lun || rcmd != cmd)
+        {
+            response.push_back(IPMI_CC_UNSPECIFIED_ERROR);
+            log<level::ERR>("DBus call/response mismatch from ipmi queue");
+            elog<InternalFailure>();
+        }
+        else
+        {
+            response.reserve(1 + responseData.size());
+            response.push_back(cc);
+            response.insert(response.end(), responseData.begin(),
+                            responseData.end());
+        }
     }
     else
     {
@@ -80,62 +134,13 @@
         errResponse.resize(1);
         errResponse[0] = IPMI_CC_INSUFFICIENT_PRIVILEGE;
         log<level::INFO>("Table: Insufficient privilege for command",
-                         entry("LUN=%x", int(command.NetFnLun.lun)),
-                         entry("NETFN=%x", int(command.NetFnLun.netFn)),
-                         entry("CMD=%x", command.cmd));
+                         entry("LUN=%x", command.lun()),
+                         entry("NETFN=%x", command.netFn()),
+                         entry("CMD=%x", command.cmd()));
         return errResponse;
     }
 
     return functor(commandData, handler);
 }
 
-std::vector<uint8_t>
-    ProviderIpmidEntry::executeCommand(std::vector<uint8_t>& commandData,
-                                       const message::Handler& handler)
-{
-    std::vector<uint8_t> response(message::parser::MAX_PAYLOAD_SIZE - 1);
-    size_t respSize = commandData.size();
-    ipmi_ret_t ipmiRC = IPMI_CC_UNSPECIFIED_ERROR;
-    std::shared_ptr<session::Session> session =
-        std::get<session::Manager&>(singletonPool)
-            .getSession(handler.sessionID);
-
-    if (session->curPrivLevel >= Entry::getPrivilege())
-    {
-        try
-        {
-            ipmiRC = functor(0, 0, reinterpret_cast<void*>(commandData.data()),
-                             reinterpret_cast<void*>(response.data() + 1),
-                             &respSize, NULL);
-        }
-        // IPMI command handlers can throw unhandled exceptions, catch those
-        // and return sane error code.
-        catch (const std::exception& e)
-        {
-            log<level::ERR>("Table: Unspecified error for command",
-                            entry("EXCEPTION=%s", e.what()),
-                            entry("LUN=%x", int(command.NetFnLun.lun)),
-                            entry("NETFN=%x", int(command.NetFnLun.netFn)),
-                            entry("CMD=%x", command.cmd));
-            respSize = 0;
-            // fall through
-        }
-    }
-    else
-    {
-        respSize = 0;
-        ipmiRC = IPMI_CC_INSUFFICIENT_PRIVILEGE;
-    }
-    /*
-     * respSize gets you the size of the response data for the IPMI command. The
-     * first byte in a response to the IPMI command is the Completion Code.
-     * So we are inserting completion code as the first byte and incrementing
-     * the response payload size by the size of the completion code.
-     */
-    response[0] = ipmiRC;
-    response.resize(respSize + sizeof(ipmi_ret_t));
-
-    return response;
-}
-
 } // namespace command
diff --git a/command_table.hpp b/command_table.hpp
index 1ce8f10..7e9df05 100644
--- a/command_table.hpp
+++ b/command_table.hpp
@@ -10,23 +10,31 @@
 namespace command
 {
 
-union CommandID
+struct CommandID
 {
-    uint32_t command;
-
-    uint8_t reserved;
-    message::PayloadType payloadType;
-
-    union
+    static constexpr size_t lunBits = 2;
+    CommandID(uint32_t command) : command(command)
     {
-        uint8_t netFn : 6;
-        uint8_t lun : 2;
+    }
 
-        uint8_t netFnLun;
-    } NetFnLun;
-
-    uint8_t cmd;
-} __attribute__((packed));
+    uint8_t netFnLun() const
+    {
+        return static_cast<uint8_t>(command >> CHAR_BIT);
+    }
+    uint8_t netFn() const
+    {
+        return netFnLun() >> lunBits;
+    }
+    uint8_t lun() const
+    {
+        return netFnLun() & ((1 << (lunBits + 1)) - 1);
+    }
+    uint8_t cmd() const
+    {
+        return static_cast<uint8_t>(command);
+    }
+    uint32_t command;
+};
 
 /**
  * CommandFunctor is the functor register for commands defined in
@@ -199,47 +207,6 @@
 };
 
 /**
- * @class ProviderIpmidEntry
- *
- * ProviderIpmidEntry is used to register commands to the Command Table, that
- * are registered by IPMI provider libraries.
- *
- */
-class ProviderIpmidEntry final : public Entry
-{
-  public:
-    ProviderIpmidEntry(CommandID command, ipmid_callback_t functor,
-                       session::Privilege privilege) :
-        Entry(command, privilege),
-        functor(functor)
-    {
-    }
-
-    /**
-     * @brief Execute the command
-     *
-     * Execute the callback handler
-     *
-     * @param[in] commandData - Request Data for the command
-     * @param[in] handler - Reference to the Message Handler
-     *
-     * @return Response data for the command
-     */
-    std::vector<uint8_t>
-        executeCommand(std::vector<uint8_t>& commandData,
-                       const message::Handler& handler) override;
-
-    virtual ~ProviderIpmidEntry() = default;
-    ProviderIpmidEntry(const ProviderIpmidEntry&) = default;
-    ProviderIpmidEntry& operator=(const ProviderIpmidEntry&) = default;
-    ProviderIpmidEntry(ProviderIpmidEntry&&) = default;
-    ProviderIpmidEntry& operator=(ProviderIpmidEntry&&) = default;
-
-  private:
-    ipmid_callback_t functor;
-};
-
-/**
  * @class Table
  *
  * Table keeps the IPMI command entries as a sorted associative container with
diff --git a/configure.ac b/configure.ac
index 05234a0..305b7f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,8 +53,7 @@
 AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd development package required])])
 
 # Checks for library functions.
-LT_INIT([dlopen disable-static shared])
-LT_LIB_DLLOAD
+LT_INIT([disable-static shared])
 
 AC_CONFIG_FILES([Makefile test/Makefile])
 AC_OUTPUT
diff --git a/main.cpp b/main.cpp
index 43ad596..04f3d44 100644
--- a/main.cpp
+++ b/main.cpp
@@ -5,7 +5,6 @@
 #include "command_table.hpp"
 #include "message.hpp"
 #include "message_handler.hpp"
-#include "provider_registration.hpp"
 #include "socket_channel.hpp"
 #include "sol_module.hpp"
 
@@ -19,7 +18,6 @@
 
 #include <phosphor-logging/log.hpp>
 #include <sdbusplus/asio/connection.hpp>
-#include <sdbusplus/timer.hpp>
 #include <tuple>
 
 using namespace phosphor::logging;
@@ -38,14 +36,6 @@
 sd_bus* bus = nullptr;
 sd_event* events = nullptr;
 
-// Global timer for network changes
-std::unique_ptr<phosphor::Timer> networkTimer = nullptr;
-
-FILE* ipmidbus = nullptr;
-static unsigned short selReservationID = 0xFFFF;
-static bool selReservationValid = false;
-sd_bus_slot* ipmid_slot = nullptr;
-
 std::shared_ptr<sdbusplus::bus::bus> sdbusp;
 
 /*
@@ -64,45 +54,6 @@
     return sdbusp;
 }
 
-/*
- * @brief Required by apphandler IPMI Provider Library
- */
-sd_event* ipmid_get_sd_event_connection()
-{
-    return events;
-}
-
-/*
- * @brief Required by apphandler IPMI Provider Library
- */
-unsigned short reserveSel(void)
-{
-    // IPMI spec, Reservation ID, the value simply increases against each
-    // execution of the Reserve SEL command.
-    if (++selReservationID == 0)
-    {
-        selReservationID = 1;
-    }
-    selReservationValid = true;
-    return selReservationID;
-}
-
-/*
- * @brief Required by apphandler IPMI Provider Library
- */
-bool checkSELReservation(unsigned short id)
-{
-    return (selReservationValid && selReservationID == id);
-}
-
-/*
- * @brief Required by apphandler IPMI Provider Library
- */
-void cancelSELReservation(void)
-{
-    selReservationValid = false;
-}
-
 EInterfaceIndex getInterfaceIndex(void)
 {
     return interfaceLAN1;
@@ -110,11 +61,6 @@
 
 int main()
 {
-    /*
-     * Required by apphandler IPMI Provider Library for logging.
-     */
-    ipmidbus = fopen("/dev/null", "w");
-
     // Connect to system bus
     auto rc = sd_bus_default_system(&bus);
     if (rc < 0)
@@ -138,9 +84,6 @@
     command::registerGUIDChangeCallback();
     cache::guid = command::getSystemGUID();
 
-    // Register all the IPMI provider libraries applicable for net-ipmid
-    provider::registerCallbackHandlers(NET_IPMID_LIB_PATH);
-
     // Register the phosphor-net-ipmid session setup commands
     command::sessionSetupCommands();
 
diff --git a/provider_registration.cpp b/provider_registration.cpp
deleted file mode 100644
index 616dc90..0000000
--- a/provider_registration.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-#include "provider_registration.hpp"
-
-#include "command_table.hpp"
-#include "main.hpp"
-
-#include <dirent.h>
-#include <dlfcn.h>
-#include <ipmid/api.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <phosphor-logging/log.hpp>
-
-using namespace phosphor::logging;
-
-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)
-    {
-        log<level::ERR>(
-            "Path not provided for registering IPMI provider libraries");
-        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;
-
-        auto lib_handler = dlopen(handlerPath.c_str(), RTLD_NOW);
-
-        if (lib_handler == NULL)
-        {
-            log<level::ERR>("Error opening provider library",
-                            entry("PATH=%s", handlerPath.c_str()),
-                            entry("ERROR=%s", dlerror()));
-        }
-        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 Privilege
- */
-void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
-                            ipmi_context_t context, ipmid_callback_t handler,
-                            ipmi_cmd_privilege_t 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)));
-}
diff --git a/provider_registration.hpp b/provider_registration.hpp
deleted file mode 100644
index ad956fc..0000000
--- a/provider_registration.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-
-namespace provider
-{
-
-/**
- * @brief Provider Library filename extension
- *
- * Autotools versions the shared libraries, so the shared libraries end with
- * extension name .so.*
- */
-
-constexpr auto PROVIDER_SONAME_EXTN = ".so.";
-
-/**
- * @brief Register Callback handlers for IPMI provider libraries
- *
- * Open the directory path for net-ipmid provider libraries and scan the
- * directory for files that end with .so.*. and dlopen the shared libraries
- * to register the handlers for the callback routines.
- *
- * @param[in] providerLibPath - Directory path for reading the IPMI provider
- *                              libraries
- */
-void registerCallbackHandlers(const char* providerLibPath);
-
-} // namespace provider