#pragma once #include "message_handler.hpp" #include #include #include #include namespace command { struct CommandID { static constexpr size_t lunBits = 2; CommandID(uint32_t command) : command(command) {} uint8_t netFnLun() const { return static_cast(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(command); } uint32_t command; }; /** * 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( const std::vector&, std::shared_ptr&)>; /** * @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 executeCommand(std::vector& commandData, std::shared_ptr 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 executeCommand(std::vector& commandData, std::shared_ptr 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 { private: struct Private {}; public: explicit Table(const Private&) {} Table() = delete; ~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; /** * @brief Get a reference to the singleton Table * * @return Table reference */ static Table& get() { static std::shared_ptr ptr = nullptr; if (!ptr) { ptr = std::make_shared
(Private()); } return *ptr; } using CommandTable = std::map>; /** * @brief Register a command * * Register a command with the command table * * @param[in] inCommand - Command ID * @param[in] entry - Command Entry * * @return: None * * @note: Duplicate registrations will be rejected. * */ void registerCommand(CommandID inCommand, std::unique_ptr&& 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 * */ void executeCommand(uint32_t inCommand, std::vector& commandData, std::shared_ptr handler); private: CommandTable commandTable; }; } // namespace command