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