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