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