1 #pragma once
2 
3 #include "message.hpp"
4 #include "session.hpp"
5 
6 #include <cstddef>
7 
8 namespace message
9 {
10 
11 namespace parser
12 {
13 
14 constexpr size_t RMCP_VERSION = 6;
15 
16 // RMCP Messages with class=IPMI should be sent with an RMCP Sequence
17 // Number of FFh to indicate that an RMCP ACK message should not be
18 // generated by the message receiver.
19 constexpr size_t RMCP_SEQ = 0xFF;
20 
21 // RMCP Message Class 7h is for IPMI
22 constexpr size_t RMCP_MESSAGE_CLASS_IPMI = 7;
23 
24 // RMCP Session Header Size
25 constexpr size_t RMCP_SESSION_HEADER_SIZE = 4;
26 
27 // RMCP/ASF Pong Message ASF Header Data Length
28 // as per IPMI spec 13.2.4
29 constexpr size_t RMCP_ASF_PONG_DATA_LEN = 16;
30 
31 // ASF IANA
32 constexpr uint32_t ASF_IANA = 4542;
33 
34 // ASF Supported Entities
35 constexpr uint32_t ASF_SUPP_ENT = 0x81;
36 
37 // ASF Supported Entities
38 constexpr uint32_t ASF_SUPP_INT = 0x00;
39 
40 // Maximum payload size
41 constexpr size_t MAX_PAYLOAD_SIZE = 255;
42 
43 enum class SessionHeader
44 {
45     IPMI15 = 0x00,
46     IPMI20 = 0x06,
47     INVALID = 0xFF,
48 };
49 
50 // RMCP Header
51 struct RmcpHeader_t
52 {
53     // RMCP Header
54     uint8_t version;
55     uint8_t reserved;
56     uint8_t rmcpSeqNum;
57     uint8_t classOfMsg;
58 } __attribute__((packed));
59 
60 struct BasicHeader_t
61 {
62     // RMCP Header
63     struct RmcpHeader_t rmcp;
64 
65     // IPMI partial session header
66     union
67     {
68         uint8_t reserved1:4;
69         uint8_t authType:4;
70         uint8_t formatType;
71     } format;
72 } __attribute__((packed));
73 
74 /**
75  * @brief Unflatten an incoming packet and prepare the IPMI message
76  *
77  * @param[in] inPacket - Incoming IPMI packet
78  *
79  * @return A tuple with IPMI message and the session header type to sent the
80  *         response packet. In case of success incoming message and session
81  *         header type. In case of failure nullptr and session header type
82  *         would be invalid.
83  */
84 std::tuple<std::shared_ptr<Message>, SessionHeader>
85     unflatten(std::vector<uint8_t>& inPacket);
86 
87 /**
88  * @brief Flatten an IPMI message and generate the IPMI packet with the
89  *        session header
90  *
91  * @param[in] outMessage - IPMI message to be flattened
92  * @param[in] authType - Session header type to be added to the IPMI
93  *                       packet
94  *
95  * @return IPMI packet on success
96  */
97 std::vector<uint8_t> flatten(const std::shared_ptr<Message>& outMessage,
98                              SessionHeader authType,
99                              const std::shared_ptr<session::Session>& session);
100 
101 } // namespace parser
102 
103 namespace ipmi15parser
104 {
105 
106 struct SessionHeader_t
107 {
108     struct parser::BasicHeader_t base;
109     uint32_t sessSeqNum;
110     uint32_t sessId;
111     // <Optional Field: AuthCode>
112     uint8_t payloadLength;
113 } __attribute__((packed));
114 
115 struct SessionTrailer_t
116 {
117     uint8_t legacyPad;
118 } __attribute__((packed));
119 
120 /**
121  * @brief Unflatten an incoming packet and prepare the IPMI message
122  *
123  * @param[in] inPacket - Incoming IPMI packet
124  *
125  * @return IPMI message in the packet on success
126  */
127 std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket);
128 
129 /**
130  * @brief Flatten an IPMI message and generate the IPMI packet with the
131  *        session header
132  *
133  * @param[in] outMessage - IPMI message to be flattened
134  *
135  * @return IPMI packet on success
136  */
137 std::vector<uint8_t> flatten(const std::shared_ptr<Message>& outMessage,
138                              const std::shared_ptr<session::Session>& session);
139 
140 } // namespace ipmi15parser
141 
142 namespace ipmi20parser
143 {
144 
145 constexpr size_t MAX_INTEGRITY_DATA_LENGTH = 12;
146 constexpr size_t PAYLOAD_ENCRYPT_MASK = 0x80;
147 constexpr size_t PAYLOAD_AUTH_MASK = 0x40;
148 
149 struct SessionHeader_t
150 {
151     struct parser::BasicHeader_t base;
152 
153     uint8_t payloadType;
154 
155     uint32_t sessId;
156     uint32_t sessSeqNum;
157     uint16_t payloadLength;
158 } __attribute__((packed));
159 
160 struct SessionTrailer_t
161 {
162     // Integrity Pad
163     uint8_t padLength;
164     uint8_t nextHeader;
165 } __attribute__((packed));
166 
167 /**
168  * @brief Unflatten an incoming packet and prepare the IPMI message
169  *
170  * @param[in] inPacket - Incoming IPMI packet
171  *
172  * @return IPMI message in the packet on success
173  */
174 std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket);
175 
176 /**
177  * @brief Flatten an IPMI message and generate the IPMI packet with the
178  *        session header
179  *
180  * @param[in] outMessage - IPMI message to be flattened
181  * @param[in] session - session handle
182  *
183  * @return IPMI packet on success
184  */
185 std::vector<uint8_t> flatten(const std::shared_ptr<Message>& outMessage,
186                              const std::shared_ptr<session::Session>& session);
187 
188 namespace internal
189 {
190 
191 /**
192  * @brief Add sequence number to the message
193  *
194  * @param[in] packet - outgoing packet to which to add sequence number
195  * @param[in] session - session handle
196  *
197  */
198 void addSequenceNumber(std::vector<uint8_t>& packet,
199                        const std::shared_ptr<session::Session>& session);
200 
201 /**
202  * @brief Verify the integrity data of the incoming IPMI packet
203  *
204  * @param[in] packet - Incoming IPMI packet
205  * @param[in] message - IPMI Message populated from the incoming packet
206  * @param[in] payloadLen - Length of the IPMI payload
207  * @param[in] session - session handle
208  *
209  */
210 bool verifyPacketIntegrity(const std::vector<uint8_t>& packet,
211                            const std::shared_ptr<Message>& message,
212                            size_t payloadLen,
213                            const std::shared_ptr<session::Session>& session);
214 
215 /**
216  * @brief Add Integrity data to the outgoing IPMI packet
217  *
218  * @param[in] packet - Outgoing IPMI packet
219  * @param[in] message - IPMI Message populated for the outgoing packet
220  * @param[in] payloadLen - Length of the IPMI payload
221  */
222 void addIntegrityData(std::vector<uint8_t>& packet,
223                       const std::shared_ptr<Message>& message,
224                       size_t payloadLen,
225                       const std::shared_ptr<session::Session>& session);
226 
227 /**
228  * @brief Decrypt the encrypted payload in the incoming IPMI packet
229  *
230  * @param[in] packet - Incoming IPMI packet
231  * @param[in] message - IPMI Message populated from the incoming packet
232  * @param[in] payloadLen - Length of encrypted IPMI payload
233  * @param[in] session - session handle
234  *
235  * @return on successful completion, return the plain text payload
236  */
237 std::vector<uint8_t>
238     decryptPayload(const std::vector<uint8_t>& packet,
239                    const std::shared_ptr<Message>& message, size_t payloadLen,
240                    const std::shared_ptr<session::Session>& session);
241 
242 /**
243  * @brief Encrypt the plain text payload for the outgoing IPMI packet
244  *
245  * @param[in] message - IPMI Message populated for the outgoing packet
246  * @param[in] session - session handle
247  *
248  * @return on successful completion, return the encrypted payload
249  */
250 std::vector<uint8_t>
251     encryptPayload(const std::shared_ptr<Message>& message,
252                    const std::shared_ptr<session::Session>& session);
253 
254 } // namespace internal
255 
256 } // namespace ipmi20parser
257 
258 #ifdef RMCP_PING
259 namespace asfparser
260 {
261 
262 // ASF message fields for RMCP Ping message
263 struct AsfMessagePing_t
264 {
265     struct parser::RmcpHeader_t rmcp;
266 
267     uint32_t iana;
268     uint8_t msgType;
269     uint8_t msgTag;
270     uint8_t reserved;
271     uint8_t dataLen;
272 } __attribute__((packed));
273 
274 // ASF message fields for RMCP Pong message
275 struct AsfMessagePong_t
276 {
277     struct AsfMessagePing_t ping;
278 
279     uint32_t iana;
280     uint32_t oemDefined;
281     uint8_t suppEntities;
282     uint8_t suppInteract;
283     uint32_t reserved1;
284     uint16_t reserved2;
285 } __attribute__((packed));
286 
287 /**
288  * @brief Unflatten an incoming packet and prepare the ASF message
289  *
290  * @param[in] inPacket - Incoming ASF packet
291  *
292  * @return ASF message in the packet on success
293  */
294 std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket);
295 
296 /**
297  * @brief Generate the ASF packet with the RMCP header
298  *
299  * @param[in] asfMsgTag - ASF Message Tag from Ping request
300  *
301  * @return ASF packet on success
302  */
303 std::vector<uint8_t> flatten(uint8_t asfMsgTag);
304 
305 } // namespace asfparser
306 #endif // RMCP_PING
307 
308 } // namespace message
309