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 // Maximum payload size
28 constexpr size_t MAX_PAYLOAD_SIZE = 255;
29 
30 enum class SessionHeader
31 {
32     IPMI15 = 0x00,
33     IPMI20 = 0x06,
34     INVALID = 0xFF,
35 };
36 
37 struct BasicHeader_t
38 {
39     // RMCP Header
40     uint8_t version;
41     uint8_t reserved;
42     uint8_t rmcpSeqNum;
43     uint8_t classOfMsg;
44 
45     // IPMI partial session header
46     union
47     {
48         uint8_t reserved1 : 4;
49         uint8_t authType : 4;
50         uint8_t formatType;
51     } format;
52 } __attribute__((packed));
53 
54 /**
55  * @brief Unflatten an incoming packet and prepare the IPMI message
56  *
57  * @param[in] inPacket - Incoming IPMI packet
58  *
59  * @return A tuple with IPMI message and the session header type to sent the
60  *         response packet. In case of success incoming message and session
61  *         header type. In case of failure nullptr and session header type
62  *         would be invalid.
63  */
64 std::tuple<std::shared_ptr<Message>, SessionHeader>
65     unflatten(std::vector<uint8_t>& inPacket);
66 
67 /**
68  * @brief Flatten an IPMI message and generate the IPMI packet with the
69  *        session header
70  *
71  * @param[in] outMessage - IPMI message to be flattened
72  * @param[in] authType - Session header type to be added to the IPMI
73  *                       packet
74  *
75  * @return IPMI packet on success
76  */
77 std::vector<uint8_t> flatten(std::shared_ptr<Message> outMessage,
78                              SessionHeader authType,
79                              std::shared_ptr<session::Session> session);
80 
81 } // namespace parser
82 
83 namespace ipmi15parser
84 {
85 
86 struct SessionHeader_t
87 {
88     struct parser::BasicHeader_t base;
89     uint32_t sessSeqNum;
90     uint32_t sessId;
91     // <Optional Field: AuthCode>
92     uint8_t payloadLength;
93 } __attribute__((packed));
94 
95 struct SessionTrailer_t
96 {
97     uint8_t legacyPad;
98 } __attribute__((packed));
99 
100 /**
101  * @brief Unflatten an incoming packet and prepare the IPMI message
102  *
103  * @param[in] inPacket - Incoming IPMI packet
104  *
105  * @return IPMI message in the packet on success
106  */
107 std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket);
108 
109 /**
110  * @brief Flatten an IPMI message and generate the IPMI packet with the
111  *        session header
112  *
113  * @param[in] outMessage - IPMI message to be flattened
114  *
115  * @return IPMI packet on success
116  */
117 std::vector<uint8_t> flatten(std::shared_ptr<Message> outMessage,
118                              std::shared_ptr<session::Session> session);
119 
120 } // namespace ipmi15parser
121 
122 namespace ipmi20parser
123 {
124 
125 constexpr size_t MAX_INTEGRITY_DATA_LENGTH = 12;
126 constexpr size_t PAYLOAD_ENCRYPT_MASK = 0x80;
127 constexpr size_t PAYLOAD_AUTH_MASK = 0x40;
128 
129 struct SessionHeader_t
130 {
131     struct parser::BasicHeader_t base;
132 
133     uint8_t payloadType;
134 
135     uint32_t sessId;
136     uint32_t sessSeqNum;
137     uint16_t payloadLength;
138 } __attribute__((packed));
139 
140 struct SessionTrailer_t
141 {
142     // Integrity Pad
143     uint8_t padLength;
144     uint8_t nextHeader;
145 } __attribute__((packed));
146 
147 /**
148  * @brief Unflatten an incoming packet and prepare the IPMI message
149  *
150  * @param[in] inPacket - Incoming IPMI packet
151  *
152  * @return IPMI message in the packet on success
153  */
154 std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket);
155 
156 /**
157  * @brief Flatten an IPMI message and generate the IPMI packet with the
158  *        session header
159  *
160  * @param[in] outMessage - IPMI message to be flattened
161  *
162  * @return IPMI packet on success
163  */
164 std::vector<uint8_t> flatten(std::shared_ptr<Message> outMessage,
165                              std::shared_ptr<session::Session> session);
166 
167 namespace internal
168 {
169 
170 /**
171  * @brief Add sequence number to the message
172  *
173  * @param[in] packet - outgoing packet to which to add sequence number
174  * @param[in] session - session handle
175  *
176  */
177 void addSequenceNumber(std::vector<uint8_t>& packet,
178                        std::shared_ptr<session::Session> session);
179 
180 /**
181  * @brief Verify the integrity data of the incoming IPMI packet
182  *
183  * @param[in] packet - Incoming IPMI packet
184  * @param[in] message - IPMI Message populated from the incoming packet
185  * @param[in] payloadLen - Length of the IPMI payload
186  *
187  */
188 bool verifyPacketIntegrity(const std::vector<uint8_t>& packet,
189                            const std::shared_ptr<Message> message,
190                            size_t payloadLen);
191 
192 /**
193  * @brief Add Integrity data to the outgoing IPMI packet
194  *
195  * @param[in] packet - Outgoing IPMI packet
196  * @param[in] message - IPMI Message populated for the outgoing packet
197  * @param[in] payloadLen - Length of the IPMI payload
198  */
199 void addIntegrityData(std::vector<uint8_t>& packet,
200                       const std::shared_ptr<Message> message,
201                       size_t payloadLen);
202 
203 /**
204  * @brief Decrypt the encrypted payload in the incoming IPMI packet
205  *
206  * @param[in] packet - Incoming IPMI packet
207  * @param[in] message - IPMI Message populated from the incoming packet
208  * @param[in] payloadLen - Length of encrypted IPMI payload
209  *
210  * @return on successful completion, return the plain text payload
211  */
212 std::vector<uint8_t> decryptPayload(const std::vector<uint8_t>& packet,
213                                     const std::shared_ptr<Message> message,
214                                     size_t payloadLen);
215 
216 /**
217  * @brief Encrypt the plain text payload for the outgoing IPMI packet
218  *
219  * @param[in] message - IPMI Message populated for the outgoing packet
220  *
221  * @return on successful completion, return the encrypted payload
222  */
223 std::vector<uint8_t> encryptPayload(std::shared_ptr<Message> message);
224 
225 } // namespace internal
226 
227 } // namespace ipmi20parser
228 
229 } // namespace message
230