blob: 03e1a48cf6137d3176c7d341d4c8722d38ea26b5 [file] [log] [blame]
#pragma once
#include "message_handler.hpp"
#include <ipmid/api.h>
#include <cstddef>
#include <functional>
#include <map>
namespace command
{
struct CommandID
{
static constexpr size_t lunBits = 2;
CommandID(uint32_t command) : command(command) {}
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
* 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>(
const std::vector<uint8_t>&, std::shared_ptr<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,
std::shared_ptr<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,
std::shared_ptr<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
{
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<Table> ptr = nullptr;
if (!ptr)
{
ptr = std::make_shared<Table>(Private());
}
return *ptr;
}
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: Duplicate registrations will be rejected.
*
*/
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
*
*/
void executeCommand(uint32_t inCommand, std::vector<uint8_t>& commandData,
std::shared_ptr<message::Handler> handler);
private:
CommandTable commandTable;
};
} // namespace command