1 #pragma once 2 3 #include "message_handler.hpp" 4 5 #include <ipmid/api.h> 6 7 #include <cstddef> 8 #include <functional> 9 #include <map> 10 11 namespace command 12 { 13 14 struct CommandID 15 { 16 static constexpr size_t lunBits = 2; CommandIDcommand::CommandID17 CommandID(uint32_t command) : command(command) {} 18 netFnLuncommand::CommandID19 uint8_t netFnLun() const 20 { 21 return static_cast<uint8_t>(command >> CHAR_BIT); 22 } netFncommand::CommandID23 uint8_t netFn() const 24 { 25 return netFnLun() >> lunBits; 26 } luncommand::CommandID27 uint8_t lun() const 28 { 29 return netFnLun() & ((1 << (lunBits + 1)) - 1); 30 } cmdcommand::CommandID31 uint8_t cmd() const 32 { 33 return static_cast<uint8_t>(command); 34 } 35 uint32_t command; 36 }; 37 38 /** 39 * CommandFunctor is the functor register for commands defined in 40 * phosphor-net-ipmid. This would take the request part of the command as a 41 * vector and a reference to the message handler. The response part of the 42 * command is returned as a vector. 43 */ 44 using CommandFunctor = std::function<std::vector<uint8_t>( 45 const std::vector<uint8_t>&, std::shared_ptr<message::Handler>&)>; 46 47 /** 48 * @struct CmdDetails 49 * 50 * Command details is used to register commands supported in phosphor-net-ipmid. 51 */ 52 struct CmdDetails 53 { 54 CommandID command; 55 CommandFunctor functor; 56 session::Privilege privilege; 57 bool sessionless; 58 }; 59 60 /** 61 * @enum NetFns 62 * 63 * A field that identifies the functional class of the message. The Network 64 * Function clusters IPMI commands into different sets. 65 */ 66 enum class NetFns 67 { 68 CHASSIS = (0x00 << 10), 69 CHASSIS_RESP = (0x01 << 10), 70 71 BRIDGE = (0x02 << 10), 72 BRIDGE_RESP = (0x03 << 10), 73 74 SENSOR = (0x04 << 10), 75 SENSOR_RESP = (0x05 << 10), 76 EVENT = (0x04 << 10), 77 EVENT_RESP = (0x05 << 10), 78 79 APP = (0x06 << 10), 80 APP_RESP = (0x07 << 10), 81 82 FIRMWARE = (0x08 << 10), 83 FIRMWARE_RESP = (0x09 << 10), 84 85 STORAGE = (0x0A << 10), 86 STORAGE_RESP = (0x0B << 10), 87 88 TRANSPORT = (0x0C << 10), 89 TRANSPORT_RESP = (0x0D << 10), 90 91 //>> 92 RESERVED_START = (0x0E << 10), 93 RESERVED_END = (0x2B << 10), 94 //<< 95 96 GROUP_EXTN = (0x2C << 10), 97 GROUP_EXTN_RESP = (0x2D << 10), 98 99 OEM = (0x2E << 10), 100 OEM_RESP = (0x2F << 10), 101 }; 102 103 /** 104 * @class Entry 105 * 106 * This is the base class for registering IPMI commands. There are two ways of 107 * registering commands to phosphor-net-ipmid, the session related commands and 108 * provider commands 109 * 110 * Every commands has a privilege level which mentions the minimum session 111 * privilege level needed to execute the command 112 */ 113 114 class Entry 115 { 116 public: Entry(CommandID command,session::Privilege privilege)117 Entry(CommandID command, session::Privilege privilege) : 118 command(command), privilege(privilege) 119 {} 120 121 /** 122 * @brief Execute the command 123 * 124 * Execute the command 125 * 126 * @param[in] commandData - Request Data for the command 127 * @param[in] handler - Reference to the Message Handler 128 * 129 * @return Response data for the command 130 */ 131 virtual std::vector<uint8_t> 132 executeCommand(std::vector<uint8_t>& commandData, 133 std::shared_ptr<message::Handler> handler) = 0; 134 getCommand() const135 auto getCommand() const 136 { 137 return command; 138 } 139 getPrivilege() const140 auto getPrivilege() const 141 { 142 return privilege; 143 } 144 145 virtual ~Entry() = default; 146 Entry(const Entry&) = default; 147 Entry& operator=(const Entry&) = default; 148 Entry(Entry&&) = default; 149 Entry& operator=(Entry&&) = default; 150 151 protected: 152 CommandID command; 153 154 // Specifies the minimum privilege level required to execute this command 155 session::Privilege privilege; 156 }; 157 158 /** 159 * @class NetIpmidEntry 160 * 161 * NetIpmidEntry is used to register commands that are consumed only in 162 * phosphor-net-ipmid. The RAKP commands, session commands and user management 163 * commands are examples of this. 164 * 165 * There are certain IPMI commands that can be executed before session can be 166 * established like Get System GUID, Get Channel Authentication Capabilities 167 * and RAKP commands. 168 */ 169 class NetIpmidEntry final : public Entry 170 { 171 public: NetIpmidEntry(CommandID command,CommandFunctor functor,session::Privilege privilege,bool sessionless)172 NetIpmidEntry(CommandID command, CommandFunctor functor, 173 session::Privilege privilege, bool sessionless) : 174 Entry(command, privilege), functor(functor), sessionless(sessionless) 175 {} 176 177 /** 178 * @brief Execute the command 179 * 180 * Execute the command 181 * 182 * @param[in] commandData - Request Data for the command 183 * @param[in] handler - Reference to the Message Handler 184 * 185 * @return Response data for the command 186 */ 187 std::vector<uint8_t> 188 executeCommand(std::vector<uint8_t>& commandData, 189 std::shared_ptr<message::Handler> handler) override; 190 191 virtual ~NetIpmidEntry() = default; 192 NetIpmidEntry(const NetIpmidEntry&) = default; 193 NetIpmidEntry& operator=(const NetIpmidEntry&) = default; 194 NetIpmidEntry(NetIpmidEntry&&) = default; 195 NetIpmidEntry& operator=(NetIpmidEntry&&) = default; 196 197 private: 198 CommandFunctor functor; 199 200 bool sessionless; 201 }; 202 203 /** 204 * @class Table 205 * 206 * Table keeps the IPMI command entries as a sorted associative container with 207 * Command ID as the unique key. It has interfaces for registering commands 208 * and executing a command. 209 */ 210 class Table 211 { 212 private: 213 struct Private 214 {}; 215 216 public: Table(const Private &)217 explicit Table(const Private&) {} 218 Table() = delete; 219 ~Table() = default; 220 // Command Table is a singleton so copy, copy-assignment, move and 221 // move assignment is deleted 222 Table(const Table&) = delete; 223 Table& operator=(const Table&) = delete; 224 Table(Table&&) = default; 225 Table& operator=(Table&&) = default; 226 227 /** 228 * @brief Get a reference to the singleton Table 229 * 230 * @return Table reference 231 */ get()232 static Table& get() 233 { 234 static std::shared_ptr<Table> ptr = nullptr; 235 if (!ptr) 236 { 237 ptr = std::make_shared<Table>(Private()); 238 } 239 return *ptr; 240 } 241 242 using CommandTable = std::map<uint32_t, std::unique_ptr<Entry>>; 243 244 /** 245 * @brief Register a command 246 * 247 * Register a command with the command table 248 * 249 * @param[in] inCommand - Command ID 250 * @param[in] entry - Command Entry 251 * 252 * @return: None 253 * 254 * @note: Duplicate registrations will be rejected. 255 * 256 */ 257 void registerCommand(CommandID inCommand, std::unique_ptr<Entry>&& entry); 258 259 /** 260 * @brief Execute the command 261 * 262 * Execute the command for the corresponding CommandID 263 * 264 * @param[in] inCommand - Command ID to execute. 265 * @param[in] commandData - Request Data for the command 266 * @param[in] handler - Reference to the Message Handler 267 * 268 */ 269 void executeCommand(uint32_t inCommand, std::vector<uint8_t>& commandData, 270 std::shared_ptr<message::Handler> handler); 271 272 private: 273 CommandTable commandTable; 274 }; 275 276 } // namespace command 277