1 #pragma once
2 
3 #include "message_handler.hpp"
4 
5 #include <ipmid/api.h>
6 
7 #include <functional>
8 #include <map>
9 
10 namespace command
11 {
12 
13 struct CommandID
14 {
15     static constexpr size_t lunBits = 2;
16     CommandID(uint32_t command) : command(command)
17     {
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>&, const 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 
118   public:
119     Entry(CommandID command, session::Privilege privilege) :
120         command(command), privilege(privilege)
121     {
122     }
123 
124     /**
125      * @brief Execute the command
126      *
127      * Execute the command
128      *
129      * @param[in] commandData - Request Data for the command
130      * @param[in] handler - Reference to the Message Handler
131      *
132      * @return Response data for the command
133      */
134     virtual std::vector<uint8_t>
135         executeCommand(std::vector<uint8_t>& commandData,
136                        std::shared_ptr<message::Handler> handler) = 0;
137 
138     auto getCommand() const
139     {
140         return command;
141     }
142 
143     auto getPrivilege() const
144     {
145         return privilege;
146     }
147 
148     virtual ~Entry() = default;
149     Entry(const Entry&) = default;
150     Entry& operator=(const Entry&) = default;
151     Entry(Entry&&) = default;
152     Entry& operator=(Entry&&) = default;
153 
154   protected:
155     CommandID command;
156 
157     // Specifies the minimum privilege level required to execute this command
158     session::Privilege privilege;
159 };
160 
161 /**
162  * @class NetIpmidEntry
163  *
164  * NetIpmidEntry is used to register commands that are consumed only in
165  * phosphor-net-ipmid. The RAKP commands, session commands and user management
166  * commands are examples of this.
167  *
168  * There are certain IPMI commands that can be executed before session can be
169  * established like Get System GUID, Get Channel Authentication Capabilities
170  * and RAKP commands.
171  */
172 class NetIpmidEntry final : public Entry
173 {
174 
175   public:
176     NetIpmidEntry(CommandID command, CommandFunctor functor,
177                   session::Privilege privilege, bool sessionless) :
178         Entry(command, privilege),
179         functor(functor), sessionless(sessionless)
180     {
181     }
182 
183     /**
184      * @brief Execute the command
185      *
186      * Execute the command
187      *
188      * @param[in] commandData - Request Data for the command
189      * @param[in] handler - Reference to the Message Handler
190      *
191      * @return Response data for the command
192      */
193     std::vector<uint8_t>
194         executeCommand(std::vector<uint8_t>& commandData,
195                        std::shared_ptr<message::Handler> handler) override;
196 
197     virtual ~NetIpmidEntry() = default;
198     NetIpmidEntry(const NetIpmidEntry&) = default;
199     NetIpmidEntry& operator=(const NetIpmidEntry&) = default;
200     NetIpmidEntry(NetIpmidEntry&&) = default;
201     NetIpmidEntry& operator=(NetIpmidEntry&&) = default;
202 
203   private:
204     CommandFunctor functor;
205 
206     bool sessionless;
207 };
208 
209 /**
210  * @class Table
211  *
212  * Table keeps the IPMI command entries as a sorted associative container with
213  * Command ID as the unique key. It has interfaces for registering commands
214  * and executing a command.
215  */
216 class Table
217 {
218   public:
219     Table() = default;
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     using CommandTable = std::map<uint32_t, std::unique_ptr<Entry>>;
229 
230     /**
231      * @brief Register a command
232      *
233      * Register a command with the command table
234      *
235      * @param[in] inCommand - Command ID
236      * @param[in] entry - Command Entry
237      *
238      * @return: None
239      *
240      * @note: Duplicate registrations will be rejected.
241      *
242      */
243     void registerCommand(CommandID inCommand, std::unique_ptr<Entry>&& entry);
244 
245     /**
246      * @brief Execute the command
247      *
248      * Execute the command for the corresponding CommandID
249      *
250      * @param[in] inCommand - Command ID to execute.
251      * @param[in] commandData - Request Data for the command
252      * @param[in] handler - Reference to the Message Handler
253      *
254      */
255     void executeCommand(uint32_t inCommand, std::vector<uint8_t>& commandData,
256                         std::shared_ptr<message::Handler> handler);
257 
258   private:
259     CommandTable commandTable;
260 };
261 
262 } // namespace command
263