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;
CommandIDcommand::CommandID17     CommandID(uint32_t command) : command(command) {}
18 
netFnLuncommand::CommandID19     uint8_t netFnLun() const
20     {
21         return static_cast<uint8_t>(command >> CHAR_BIT);
22     }
netFncommand::CommandID23     uint8_t netFn() const
24     {
25         return netFnLun() >> lunBits;
26     }
luncommand::CommandID27     uint8_t lun() const
28     {
29         return netFnLun() & ((1 << (lunBits + 1)) - 1);
30     }
cmdcommand::CommandID31     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:
Entry(CommandID command,session::Privilege privilege)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 
getCommand() const135     auto getCommand() const
136     {
137         return command;
138     }
139 
getPrivilege() const140     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:
NetIpmidEntry(CommandID command,CommandFunctor functor,session::Privilege privilege,bool sessionless)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:
Table(const Private &)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      */
get()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