Command Router to handle commands

This class encapsulates the details regarding the execution of the
command and has routines for registering and execution of
the command.

Change-Id: Idf26e1f60f9f89aa5261fde89577ec7ddc26c096
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/command_table.hpp b/command_table.hpp
new file mode 100644
index 0000000..40e8020
--- /dev/null
+++ b/command_table.hpp
@@ -0,0 +1,255 @@
+#pragma once
+
+#include <functional>
+#include <map>
+
+#include "message_handler.hpp"
+
+namespace command
+{
+
+union CommandID
+{
+    uint32_t command;
+
+    uint8_t reserved;
+    message::PayloadType payloadType;
+
+    union
+    {
+        uint8_t netFn: 6;
+        uint8_t lun: 2;
+
+        uint8_t netFnLun;
+    } NetFnLun;
+
+    uint8_t cmd;
+} __attribute__((packed));
+
+/*
+ * CommandFunctor is the functor register for commands defined in
+ * phosphor-net-ipmid. This would take the request part of the command as a
+ * vector and a reference to the message handler. The response part of the
+ * command is returned as a vector.
+ */
+using CommandFunctor = std::function<std::vector<uint8_t>(
+                           std::vector<uint8_t>&, const message::Handler&)>;
+
+/*
+ * @struct CmdDetails
+ *
+ * Command details is used to register commands supported in phosphor-net-ipmid.
+ */
+struct CmdDetails
+{
+    CommandID command;
+    CommandFunctor functor;
+    session::Privilege privilege;
+    bool sessionless;
+};
+
+/*
+ * @enum NetFns
+ *
+ * A field that identifies the functional class of the message. The Network
+ * Function clusters IPMI commands into different sets.
+ */
+enum class NetFns
+{
+    CHASSIS            = (0x00 << 10),
+    CHASSIS_RESP       = (0x01 << 10),
+
+    BRIDGE             = (0x02 << 10),
+    BRIDGE_RESP        = (0x03 << 10),
+
+    SENSOR             = (0x04 << 10),
+    SENSOR_RESP        = (0x05 << 10),
+    EVENT              = (0x04 << 10),
+    EVENT_RESP         = (0x05 << 10),
+
+    APP                = (0x06 << 10),
+    APP_RESP           = (0x07 << 10),
+
+    FIRMWARE           = (0x08 << 10),
+    FIRMWARE_RESP      = (0x09 << 10),
+
+    STORAGE            = (0x0A << 10),
+    STORAGE_RESP       = (0x0B << 10),
+
+    TRANSPORT          = (0x0C << 10),
+    TRANSPORT_RESP     = (0x0D << 10),
+
+    //>>
+    RESERVED_START     = (0x0E << 10),
+    RESERVED_END       = (0x2B << 10),
+    //<<
+
+    GROUP_EXTN         = (0x2C << 10),
+    GROUP_EXTN_RESP    = (0x2D << 10),
+
+    OEM                = (0x2E << 10),
+    OEM_RESP           = (0x2F << 10),
+};
+
+/*
+ * @class Entry
+ *
+ * This is the base class for registering IPMI commands. There are two ways of
+ * registering commands to phosphor-net-ipmid, the session related commands and
+ * provider commands
+ *
+ * Every commands has a privilege level which mentions the minimum session
+ * privilege level needed to execute the command
+ */
+
+class Entry
+{
+
+    public:
+        Entry(CommandID command, session::Privilege privilege):
+            command(command),
+            privilege(privilege) {}
+
+        /**
+         * @brief Execute the command
+         *
+         * Execute the command
+         *
+         * @param[in] commandData - Request Data for the command
+         * @param[in] handler - Reference to the Message Handler
+         *
+         * @return Response data for the command
+         */
+        virtual std::vector<uint8_t> executeCommand(
+            std::vector<uint8_t>& commandData,
+            const message::Handler& handler) = 0;
+
+        auto getCommand() const
+        {
+            return command;
+        }
+
+        auto getPrivilege() const
+        {
+            return privilege;
+        }
+
+        virtual ~Entry() = default;
+        Entry(const Entry&) = default;
+        Entry& operator=(const Entry&) = default;
+        Entry(Entry&&) = default;
+        Entry& operator=(Entry&&) = default;
+
+    protected:
+        CommandID command;
+
+        //Specifies the minimum privilege level required to execute this command
+        session::Privilege privilege;
+};
+
+/*
+ * @class NetIpmidEntry
+ *
+ * NetIpmidEntry is used to register commands that are consumed only in
+ * phosphor-net-ipmid. The RAKP commands, session commands and user management
+ * commands are examples of this.
+ *
+ * There are certain IPMI commands that can be executed before session can be
+ * established like Get System GUID, Get Channel Authentication Capabilities
+ * and RAKP commands.
+ */
+class NetIpmidEntry final: public Entry
+{
+
+    public:
+        NetIpmidEntry(CommandID command,
+                      CommandFunctor functor,
+                      session::Privilege privilege,
+                      bool sessionless):
+            Entry(command, privilege),
+            functor(functor),
+            sessionless(sessionless) {}
+
+        /**
+         * @brief Execute the command
+         *
+         * Execute the command
+         *
+         * @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 ~NetIpmidEntry() = default;
+        NetIpmidEntry(const NetIpmidEntry&) = default;
+        NetIpmidEntry& operator=(const NetIpmidEntry&) = default;
+        NetIpmidEntry(NetIpmidEntry&&) = default;
+        NetIpmidEntry& operator=(NetIpmidEntry&&) = default;
+
+    private:
+        CommandFunctor functor;
+
+        bool sessionless;
+};
+
+/*
+ * @class Table
+ *
+ * Table keeps the IPMI command entries as a sorted associative container with
+ * Command ID as the unique key. It has interfaces for registering commands
+ * and executing a command.
+ */
+class Table
+{
+    public:
+
+        Table() = default;
+        ~Table() = default;
+        // Command Table is a singleton so copy, copy-assignment, move and
+        // move assignment is deleted
+        Table(const Table&) = delete;
+        Table& operator=(const Table&) = delete;
+        Table(Table&&) = default;
+        Table& operator=(Table&&) = default;
+
+        using CommandTable = std::map<uint32_t, std::unique_ptr<Entry>>;
+
+        /**
+         * @brief Register a command
+         *
+         * Register a command with the command table
+         *
+         * @param[in] inCommand - Command ID
+         * @param[in] entry - Command Entry
+         *
+         * @return: None
+         *
+         * @note Registering an already registered command will overwrite the
+         *       existing entry with the new one.
+         */
+        void registerCommand(CommandID inCommand,
+                             std::unique_ptr<Entry>&& entry);
+
+        /**
+         * @brief Execute the command
+         *
+         * Execute the command for the corresponding CommandID
+         *
+         * @param[in] inCommand - Command ID to execute.
+         * @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(uint32_t inCommand,
+                                            std::vector<uint8_t>& commandData,
+                                            const message::Handler& handler);
+    private:
+        CommandTable commandTable;
+};
+
+}// namespace command