xref: /openbmc/phosphor-net-ipmid/command_table.hpp (revision bc8958fec769e4c3f99b2fb8b64dd45eb414cf5b)
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     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>&, std::shared_ptr<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   public:
118     Entry(CommandID command, session::Privilege privilege) :
119         command(command), privilege(privilege)
120     {}
121 
122     /**
123      * @brief Execute the command
124      *
125      * Execute the command
126      *
127      * @param[in] commandData - Request Data for the command
128      * @param[in] handler - Reference to the Message Handler
129      *
130      * @return Response data for the command
131      */
132     virtual std::vector<uint8_t>
133         executeCommand(std::vector<uint8_t>& commandData,
134                        std::shared_ptr<message::Handler> handler) = 0;
135 
136     auto getCommand() const
137     {
138         return command;
139     }
140 
141     auto getPrivilege() const
142     {
143         return privilege;
144     }
145 
146     virtual ~Entry() = default;
147     Entry(const Entry&) = default;
148     Entry& operator=(const Entry&) = default;
149     Entry(Entry&&) = default;
150     Entry& operator=(Entry&&) = default;
151 
152   protected:
153     CommandID command;
154 
155     // Specifies the minimum privilege level required to execute this command
156     session::Privilege privilege;
157 };
158 
159 /**
160  * @class NetIpmidEntry
161  *
162  * NetIpmidEntry is used to register commands that are consumed only in
163  * phosphor-net-ipmid. The RAKP commands, session commands and user management
164  * commands are examples of this.
165  *
166  * There are certain IPMI commands that can be executed before session can be
167  * established like Get System GUID, Get Channel Authentication Capabilities
168  * and RAKP commands.
169  */
170 class NetIpmidEntry final : public Entry
171 {
172   public:
173     NetIpmidEntry(CommandID command, CommandFunctor functor,
174                   session::Privilege privilege, bool sessionless) :
175         Entry(command, privilege),
176         functor(functor), sessionless(sessionless)
177     {}
178 
179     /**
180      * @brief Execute the command
181      *
182      * Execute the command
183      *
184      * @param[in] commandData - Request Data for the command
185      * @param[in] handler - Reference to the Message Handler
186      *
187      * @return Response data for the command
188      */
189     std::vector<uint8_t>
190         executeCommand(std::vector<uint8_t>& commandData,
191                        std::shared_ptr<message::Handler> handler) override;
192 
193     virtual ~NetIpmidEntry() = default;
194     NetIpmidEntry(const NetIpmidEntry&) = default;
195     NetIpmidEntry& operator=(const NetIpmidEntry&) = default;
196     NetIpmidEntry(NetIpmidEntry&&) = default;
197     NetIpmidEntry& operator=(NetIpmidEntry&&) = default;
198 
199   private:
200     CommandFunctor functor;
201 
202     bool sessionless;
203 };
204 
205 /**
206  * @class Table
207  *
208  * Table keeps the IPMI command entries as a sorted associative container with
209  * Command ID as the unique key. It has interfaces for registering commands
210  * and executing a command.
211  */
212 class Table
213 {
214   private:
215     struct Private
216     {};
217 
218   public:
219     explicit Table(const Private&)
220     {}
221     Table() = delete;
222     ~Table() = default;
223     // Command Table is a singleton so copy, copy-assignment, move and
224     // move assignment is deleted
225     Table(const Table&) = delete;
226     Table& operator=(const Table&) = delete;
227     Table(Table&&) = default;
228     Table& operator=(Table&&) = default;
229 
230     /**
231      * @brief Get a reference to the singleton Table
232      *
233      * @return Table reference
234      */
235     static Table& get()
236     {
237         static std::shared_ptr<Table> ptr = nullptr;
238         if (!ptr)
239         {
240             ptr = std::make_shared<Table>(Private());
241         }
242         return *ptr;
243     }
244 
245     using CommandTable = std::map<uint32_t, std::unique_ptr<Entry>>;
246 
247     /**
248      * @brief Register a command
249      *
250      * Register a command with the command table
251      *
252      * @param[in] inCommand - Command ID
253      * @param[in] entry - Command Entry
254      *
255      * @return: None
256      *
257      * @note: Duplicate registrations will be rejected.
258      *
259      */
260     void registerCommand(CommandID inCommand, std::unique_ptr<Entry>&& entry);
261 
262     /**
263      * @brief Execute the command
264      *
265      * Execute the command for the corresponding CommandID
266      *
267      * @param[in] inCommand - Command ID to execute.
268      * @param[in] commandData - Request Data for the command
269      * @param[in] handler - Reference to the Message Handler
270      *
271      */
272     void executeCommand(uint32_t inCommand, std::vector<uint8_t>& commandData,
273                         std::shared_ptr<message::Handler> handler);
274 
275   private:
276     CommandTable commandTable;
277 };
278 
279 } // namespace command
280