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 uint8_t netFnLun() const 20 { 21 return static_cast<uint8_t>(command >> CHAR_BIT); 22 } 23 uint8_t netFn() const 24 { 25 return netFnLun() >> lunBits; 26 } 27 uint8_t lun() const 28 { 29 return netFnLun() & ((1 << (lunBits + 1)) - 1); 30 } 31 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: 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 135 auto getCommand() const 136 { 137 return command; 138 } 139 140 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: 172 NetIpmidEntry(CommandID command, CommandFunctor functor, 173 session::Privilege privilege, bool sessionless) : 174 Entry(command, privilege), 175 functor(functor), sessionless(sessionless) 176 {} 177 178 /** 179 * @brief Execute the command 180 * 181 * Execute the command 182 * 183 * @param[in] commandData - Request Data for the command 184 * @param[in] handler - Reference to the Message Handler 185 * 186 * @return Response data for the command 187 */ 188 std::vector<uint8_t> 189 executeCommand(std::vector<uint8_t>& commandData, 190 std::shared_ptr<message::Handler> handler) override; 191 192 virtual ~NetIpmidEntry() = default; 193 NetIpmidEntry(const NetIpmidEntry&) = default; 194 NetIpmidEntry& operator=(const NetIpmidEntry&) = default; 195 NetIpmidEntry(NetIpmidEntry&&) = default; 196 NetIpmidEntry& operator=(NetIpmidEntry&&) = default; 197 198 private: 199 CommandFunctor functor; 200 201 bool sessionless; 202 }; 203 204 /** 205 * @class Table 206 * 207 * Table keeps the IPMI command entries as a sorted associative container with 208 * Command ID as the unique key. It has interfaces for registering commands 209 * and executing a command. 210 */ 211 class Table 212 { 213 private: 214 struct Private 215 {}; 216 217 public: 218 explicit Table(const Private&) {} 219 Table() = delete; 220 ~Table() = default; 221 // Command Table is a singleton so copy, copy-assignment, move and 222 // move assignment is deleted 223 Table(const Table&) = delete; 224 Table& operator=(const Table&) = delete; 225 Table(Table&&) = default; 226 Table& operator=(Table&&) = default; 227 228 /** 229 * @brief Get a reference to the singleton Table 230 * 231 * @return Table reference 232 */ 233 static Table& get() 234 { 235 static std::shared_ptr<Table> ptr = nullptr; 236 if (!ptr) 237 { 238 ptr = std::make_shared<Table>(Private()); 239 } 240 return *ptr; 241 } 242 243 using CommandTable = std::map<uint32_t, std::unique_ptr<Entry>>; 244 245 /** 246 * @brief Register a command 247 * 248 * Register a command with the command table 249 * 250 * @param[in] inCommand - Command ID 251 * @param[in] entry - Command Entry 252 * 253 * @return: None 254 * 255 * @note: Duplicate registrations will be rejected. 256 * 257 */ 258 void registerCommand(CommandID inCommand, std::unique_ptr<Entry>&& entry); 259 260 /** 261 * @brief Execute the command 262 * 263 * Execute the command for the corresponding CommandID 264 * 265 * @param[in] inCommand - Command ID to execute. 266 * @param[in] commandData - Request Data for the command 267 * @param[in] handler - Reference to the Message Handler 268 * 269 */ 270 void executeCommand(uint32_t inCommand, std::vector<uint8_t>& commandData, 271 std::shared_ptr<message::Handler> handler); 272 273 private: 274 CommandTable commandTable; 275 }; 276 277 } // namespace command 278