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), functor(functor), sessionless(sessionless)
175     {}
176 
177     /**
178      * @brief Execute the command
179      *
180      * Execute the command
181      *
182      * @param[in] commandData - Request Data for the command
183      * @param[in] handler - Reference to the Message Handler
184      *
185      * @return Response data for the command
186      */
187     std::vector<uint8_t>
188         executeCommand(std::vector<uint8_t>& commandData,
189                        std::shared_ptr<message::Handler> handler) override;
190 
191     virtual ~NetIpmidEntry() = default;
192     NetIpmidEntry(const NetIpmidEntry&) = default;
193     NetIpmidEntry& operator=(const NetIpmidEntry&) = default;
194     NetIpmidEntry(NetIpmidEntry&&) = default;
195     NetIpmidEntry& operator=(NetIpmidEntry&&) = default;
196 
197   private:
198     CommandFunctor functor;
199 
200     bool sessionless;
201 };
202 
203 /**
204  * @class Table
205  *
206  * Table keeps the IPMI command entries as a sorted associative container with
207  * Command ID as the unique key. It has interfaces for registering commands
208  * and executing a command.
209  */
210 class Table
211 {
212   private:
213     struct Private
214     {};
215 
216   public:
Table(const Private &)217     explicit Table(const Private&) {}
218     Table() = delete;
219     ~Table() = default;
220     // Command Table is a singleton so copy, copy-assignment, move and
221     // move assignment is deleted
222     Table(const Table&) = delete;
223     Table& operator=(const Table&) = delete;
224     Table(Table&&) = default;
225     Table& operator=(Table&&) = default;
226 
227     /**
228      * @brief Get a reference to the singleton Table
229      *
230      * @return Table reference
231      */
get()232     static Table& get()
233     {
234         static std::shared_ptr<Table> ptr = nullptr;
235         if (!ptr)
236         {
237             ptr = std::make_shared<Table>(Private());
238         }
239         return *ptr;
240     }
241 
242     using CommandTable = std::map<uint32_t, std::unique_ptr<Entry>>;
243 
244     /**
245      * @brief Register a command
246      *
247      * Register a command with the command table
248      *
249      * @param[in] inCommand - Command ID
250      * @param[in] entry - Command Entry
251      *
252      * @return: None
253      *
254      * @note: Duplicate registrations will be rejected.
255      *
256      */
257     void registerCommand(CommandID inCommand, std::unique_ptr<Entry>&& entry);
258 
259     /**
260      * @brief Execute the command
261      *
262      * Execute the command for the corresponding CommandID
263      *
264      * @param[in] inCommand - Command ID to execute.
265      * @param[in] commandData - Request Data for the command
266      * @param[in] handler - Reference to the Message Handler
267      *
268      */
269     void executeCommand(uint32_t inCommand, std::vector<uint8_t>& commandData,
270                         std::shared_ptr<message::Handler> handler);
271 
272   private:
273     CommandTable commandTable;
274 };
275 
276 } // namespace command
277