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