blob: 9c7218c712594ec8e5046fdce4fc7bf340a1ad89 [file] [log] [blame]
Tom Joseph4e57ada2016-08-10 06:51:12 -05001#include "message_parsers.hpp"
2
Tom Joseph4e57ada2016-08-10 06:51:12 -05003#include "endian.hpp"
4#include "main.hpp"
5#include "message.hpp"
6#include "sessions_manager.hpp"
7
Vernon Mauery9e801a22018-10-12 13:20:49 -07008#include <memory>
9
Tom Joseph4e57ada2016-08-10 06:51:12 -050010namespace message
11{
12
13namespace parser
14{
15
Vernon Maueryd999ffc2018-10-25 09:16:05 -070016std::tuple<std::shared_ptr<Message>, SessionHeader>
Vernon Mauery9e801a22018-10-12 13:20:49 -070017 unflatten(std::vector<uint8_t>& inPacket)
Tom Joseph4e57ada2016-08-10 06:51:12 -050018{
19 // Check if the packet has atleast the size of the RMCP Header
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030020 if (inPacket.size() < sizeof(RmcpHeader_t))
Tom Joseph4e57ada2016-08-10 06:51:12 -050021 {
22 throw std::runtime_error("RMCP Header missing");
23 }
24
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030025 auto rmcpHeaderPtr = reinterpret_cast<RmcpHeader_t*>(inPacket.data());
Tom Joseph4e57ada2016-08-10 06:51:12 -050026
27 // Verify if the fields in the RMCP header conforms to the specification
28 if ((rmcpHeaderPtr->version != RMCP_VERSION) ||
29 (rmcpHeaderPtr->rmcpSeqNum != RMCP_SEQ) ||
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030030 (rmcpHeaderPtr->classOfMsg < static_cast<uint8_t>(ClassOfMsg::ASF) &&
31 rmcpHeaderPtr->classOfMsg > static_cast<uint8_t>(ClassOfMsg::OEM)))
Tom Joseph4e57ada2016-08-10 06:51:12 -050032 {
33 throw std::runtime_error("RMCP Header is invalid");
34 }
35
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030036 if (rmcpHeaderPtr->classOfMsg == static_cast<uint8_t>(ClassOfMsg::ASF))
37 {
38#ifndef RMCP_PING
39 throw std::runtime_error("RMCP Ping is not supported");
40#else
41 return std::make_tuple(asfparser::unflatten(inPacket),
42 SessionHeader::IPMI15);
43#endif // RMCP_PING
44 }
45
46 auto sessionHeaderPtr = reinterpret_cast<BasicHeader_t*>(inPacket.data());
47
Tom Joseph4e57ada2016-08-10 06:51:12 -050048 // Read the Session Header and invoke the parser corresponding to the
49 // header type
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030050 switch (static_cast<SessionHeader>(sessionHeaderPtr->format.formatType))
Tom Joseph4e57ada2016-08-10 06:51:12 -050051 {
52 case SessionHeader::IPMI15:
53 {
54 return std::make_tuple(ipmi15parser::unflatten(inPacket),
55 SessionHeader::IPMI15);
56 }
57 case SessionHeader::IPMI20:
58 {
59 return std::make_tuple(ipmi20parser::unflatten(inPacket),
60 SessionHeader::IPMI20);
61 }
62 default:
63 {
64 throw std::runtime_error("Invalid Session Header");
65 }
66 }
67}
68
Vernon Maueryd999ffc2018-10-25 09:16:05 -070069std::vector<uint8_t> flatten(std::shared_ptr<Message> outMessage,
Vernon Mauery224f36a2018-10-25 08:52:23 -070070 SessionHeader authType,
71 std::shared_ptr<session::Session> session)
Tom Joseph4e57ada2016-08-10 06:51:12 -050072{
73 // Call the flatten routine based on the header type
74 switch (authType)
75 {
76 case SessionHeader::IPMI15:
77 {
78 return ipmi15parser::flatten(outMessage, session);
79 }
80 case SessionHeader::IPMI20:
81 {
82 return ipmi20parser::flatten(outMessage, session);
83 }
84 default:
85 {
86 return {};
87 }
88 }
89}
90
91} // namespace parser
92
93namespace ipmi15parser
94{
95
Vernon Maueryd999ffc2018-10-25 09:16:05 -070096std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket)
Tom Joseph4e57ada2016-08-10 06:51:12 -050097{
Tom Joseph4e57ada2016-08-10 06:51:12 -050098 if (inPacket.size() < sizeof(SessionHeader_t))
99 {
100 throw std::runtime_error("IPMI1.5 Session Header Missing");
101 }
102
Tom Joseph4e57ada2016-08-10 06:51:12 -0500103 auto header = reinterpret_cast<SessionHeader_t*>(inPacket.data());
104
Vernon Mauery779e7e12021-06-08 16:24:45 -0700105 uint32_t sessionID = endian::from_ipmi(header->sessId);
106 if (sessionID != session::sessionZero)
107 {
108 throw std::runtime_error("IPMI1.5 session packets are unsupported");
109 }
110
111 auto message = std::make_shared<Message>();
112
Tom Joseph4e57ada2016-08-10 06:51:12 -0500113 message->payloadType = PayloadType::IPMI;
Vernon Mauery779e7e12021-06-08 16:24:45 -0700114 message->bmcSessionID = session::sessionZero;
Tom Joseph6a560762017-01-10 15:30:28 +0530115 message->sessionSeqNum = endian::from_ipmi(header->sessSeqNum);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500116 message->isPacketEncrypted = false;
117 message->isPacketAuthenticated = false;
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300118 message->rmcpMsgClass =
119 static_cast<ClassOfMsg>(header->base.rmcp.classOfMsg);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500120
Zhikui Ren2b1edef2020-07-24 14:32:13 -0700121 // Confirm the number of data bytes received correlates to
122 // the packet length in the header
Vernon Mauerya71b1ba2021-06-08 15:53:46 -0700123 size_t payloadLen = header->payloadLength;
124 if ((payloadLen == 0) || (inPacket.size() < (sizeof(*header) + payloadLen)))
Zhikui Ren2b1edef2020-07-24 14:32:13 -0700125 {
126 throw std::runtime_error("Invalid data length");
127 }
128
Vernon Mauery9e801a22018-10-12 13:20:49 -0700129 (message->payload)
130 .assign(inPacket.data() + sizeof(SessionHeader_t),
131 inPacket.data() + sizeof(SessionHeader_t) + payloadLen);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500132
133 return message;
134}
135
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700136std::vector<uint8_t> flatten(std::shared_ptr<Message> outMessage,
Vernon Mauery224f36a2018-10-25 08:52:23 -0700137 std::shared_ptr<session::Session> session)
Tom Joseph4e57ada2016-08-10 06:51:12 -0500138{
139 std::vector<uint8_t> packet(sizeof(SessionHeader_t));
140
141 // Insert Session Header into the Packet
142 auto header = reinterpret_cast<SessionHeader_t*>(packet.data());
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300143 header->base.rmcp.version = parser::RMCP_VERSION;
144 header->base.rmcp.reserved = 0x00;
145 header->base.rmcp.rmcpSeqNum = parser::RMCP_SEQ;
146 header->base.rmcp.classOfMsg = static_cast<uint8_t>(ClassOfMsg::IPMI);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500147 header->base.format.formatType =
148 static_cast<uint8_t>(parser::SessionHeader::IPMI15);
149 header->sessSeqNum = 0;
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700150 header->sessId = endian::to_ipmi(outMessage->rcSessionID);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500151
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700152 header->payloadLength = static_cast<uint8_t>(outMessage->payload.size());
Tom Joseph4e57ada2016-08-10 06:51:12 -0500153
154 // Insert the Payload into the Packet
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700155 packet.insert(packet.end(), outMessage->payload.begin(),
156 outMessage->payload.end());
Tom Joseph4e57ada2016-08-10 06:51:12 -0500157
158 // Insert the Session Trailer
159 packet.resize(packet.size() + sizeof(SessionTrailer_t));
Vernon Mauery9e801a22018-10-12 13:20:49 -0700160 auto trailer =
161 reinterpret_cast<SessionTrailer_t*>(packet.data() + packet.size());
Tom Joseph4e57ada2016-08-10 06:51:12 -0500162 trailer->legacyPad = 0x00;
163
164 return packet;
165}
166
167} // namespace ipmi15parser
168
169namespace ipmi20parser
170{
171
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700172std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket)
Tom Joseph4e57ada2016-08-10 06:51:12 -0500173{
174 // Check if the packet has atleast the Session Header
175 if (inPacket.size() < sizeof(SessionHeader_t))
176 {
177 throw std::runtime_error("IPMI2.0 Session Header Missing");
178 }
179
Tom Joseph4e57ada2016-08-10 06:51:12 -0500180 auto header = reinterpret_cast<SessionHeader_t*>(inPacket.data());
181
Vernon Mauery1ab1c6b2021-06-08 15:54:41 -0700182 uint32_t sessionID = endian::from_ipmi(header->sessId);
183
Vernon Mauery2085ae02021-06-10 11:51:00 -0700184 auto session = session::Manager::get().getSession(sessionID);
Vernon Mauery1ab1c6b2021-06-08 15:54:41 -0700185 if (!session)
186 {
187 throw std::runtime_error("RMCP+ message from unknown session");
188 }
189
190 auto message = std::make_shared<Message>();
191
Vernon Mauery9e801a22018-10-12 13:20:49 -0700192 message->payloadType = static_cast<PayloadType>(header->payloadType & 0x3F);
Vernon Mauery1ab1c6b2021-06-08 15:54:41 -0700193 message->bmcSessionID = sessionID;
Tom Joseph6a560762017-01-10 15:30:28 +0530194 message->sessionSeqNum = endian::from_ipmi(header->sessSeqNum);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500195 message->isPacketEncrypted =
196 ((header->payloadType & PAYLOAD_ENCRYPT_MASK) ? true : false);
197 message->isPacketAuthenticated =
198 ((header->payloadType & PAYLOAD_AUTH_MASK) ? true : false);
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300199 message->rmcpMsgClass =
200 static_cast<ClassOfMsg>(header->base.rmcp.classOfMsg);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500201
Vernon Mauerya71b1ba2021-06-08 15:53:46 -0700202 // Confirm the number of data bytes received correlates to
203 // the packet length in the header
204 size_t payloadLen = endian::from_ipmi(header->payloadLength);
205 if ((payloadLen == 0) || (inPacket.size() < (sizeof(*header) + payloadLen)))
206 {
207 throw std::runtime_error("Invalid data length");
208 }
Tom Joseph4e57ada2016-08-10 06:51:12 -0500209
Vernon Mauery1ab1c6b2021-06-08 15:54:41 -0700210 bool integrityMismatch =
211 session->isIntegrityAlgoEnabled() && !message->isPacketAuthenticated;
212 bool encryptMismatch =
213 session->isCryptAlgoEnabled() && !message->isPacketEncrypted;
214
215 if (sessionID != session::sessionZero &&
216 (integrityMismatch || encryptMismatch))
217 {
218 throw std::runtime_error("unencrypted or unauthenticated message");
219 }
220
Tom Joseph5fa487c2017-01-20 12:42:39 +0530221 if (message->isPacketAuthenticated)
Tom Joseph64703f42017-01-10 17:03:48 +0530222 {
Lei YUce1f4fc2022-07-12 20:22:17 +0800223 if (!(internal::verifyPacketIntegrity(inPacket, message, payloadLen,
224 session)))
Tom Joseph64703f42017-01-10 17:03:48 +0530225 {
226 throw std::runtime_error("Packet Integrity check failed");
227 }
228 }
229
Tom Joseph78478a82017-01-26 14:24:29 +0530230 // Decrypt the payload if the payload is encrypted
231 if (message->isPacketEncrypted)
232 {
233 // Assign the decrypted payload to the IPMI Message
Vernon Mauery9e801a22018-10-12 13:20:49 -0700234 message->payload =
Lei YUce1f4fc2022-07-12 20:22:17 +0800235 internal::decryptPayload(inPacket, message, payloadLen, session);
Tom Joseph78478a82017-01-26 14:24:29 +0530236 }
237 else
238 {
239 message->payload.assign(inPacket.begin() + sizeof(SessionHeader_t),
240 inPacket.begin() + sizeof(SessionHeader_t) +
Vernon Mauery9e801a22018-10-12 13:20:49 -0700241 payloadLen);
Tom Joseph78478a82017-01-26 14:24:29 +0530242 }
243
Tom Joseph4e57ada2016-08-10 06:51:12 -0500244 return message;
245}
246
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700247std::vector<uint8_t> flatten(std::shared_ptr<Message> outMessage,
Vernon Mauery224f36a2018-10-25 08:52:23 -0700248 std::shared_ptr<session::Session> session)
Tom Joseph4e57ada2016-08-10 06:51:12 -0500249{
250 std::vector<uint8_t> packet(sizeof(SessionHeader_t));
251
252 SessionHeader_t* header = reinterpret_cast<SessionHeader_t*>(packet.data());
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300253 header->base.rmcp.version = parser::RMCP_VERSION;
254 header->base.rmcp.reserved = 0x00;
255 header->base.rmcp.rmcpSeqNum = parser::RMCP_SEQ;
256 header->base.rmcp.classOfMsg = static_cast<uint8_t>(ClassOfMsg::IPMI);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500257 header->base.format.formatType =
258 static_cast<uint8_t>(parser::SessionHeader::IPMI20);
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700259 header->payloadType = static_cast<uint8_t>(outMessage->payloadType);
260 header->sessId = endian::to_ipmi(outMessage->rcSessionID);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500261
262 // Add session sequence number
263 internal::addSequenceNumber(packet, session);
264
Tom Joseph1404bca2017-01-26 14:17:02 +0530265 size_t payloadLen = 0;
266
Tom Joseph75362832017-01-26 15:17:04 +0530267 // Encrypt the payload if needed
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700268 if (outMessage->isPacketEncrypted)
Tom Joseph75362832017-01-26 15:17:04 +0530269 {
270 header->payloadType |= PAYLOAD_ENCRYPT_MASK;
Lei YUce1f4fc2022-07-12 20:22:17 +0800271 auto cipherPayload = internal::encryptPayload(outMessage, session);
Tom Joseph75362832017-01-26 15:17:04 +0530272 payloadLen = cipherPayload.size();
273 header->payloadLength = endian::to_ipmi<uint16_t>(cipherPayload.size());
274
275 // Insert the encrypted payload into the outgoing IPMI packet
276 packet.insert(packet.end(), cipherPayload.begin(), cipherPayload.end());
277 }
278 else
279 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700280 header->payloadLength =
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700281 endian::to_ipmi<uint16_t>(outMessage->payload.size());
282 payloadLen = outMessage->payload.size();
Tom Joseph75362832017-01-26 15:17:04 +0530283
284 // Insert the Payload into the Packet
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700285 packet.insert(packet.end(), outMessage->payload.begin(),
286 outMessage->payload.end());
Tom Joseph75362832017-01-26 15:17:04 +0530287 }
Tom Joseph4e57ada2016-08-10 06:51:12 -0500288
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700289 if (outMessage->isPacketAuthenticated)
Tom Joseph64703f42017-01-10 17:03:48 +0530290 {
Tom Josephb882dbb2019-02-09 23:13:48 +0530291 header = reinterpret_cast<SessionHeader_t*>(packet.data());
292 header->payloadType |= PAYLOAD_AUTH_MASK;
Lei YUce1f4fc2022-07-12 20:22:17 +0800293 internal::addIntegrityData(packet, outMessage, payloadLen, session);
Tom Joseph64703f42017-01-10 17:03:48 +0530294 }
295
Tom Joseph4e57ada2016-08-10 06:51:12 -0500296 return packet;
297}
298
299namespace internal
300{
301
Vernon Mauery224f36a2018-10-25 08:52:23 -0700302void addSequenceNumber(std::vector<uint8_t>& packet,
303 std::shared_ptr<session::Session> session)
Tom Joseph4e57ada2016-08-10 06:51:12 -0500304{
305 SessionHeader_t* header = reinterpret_cast<SessionHeader_t*>(packet.data());
306
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530307 if (header->sessId == session::sessionZero)
Tom Joseph4e57ada2016-08-10 06:51:12 -0500308 {
309 header->sessSeqNum = 0x00;
310 }
311 else
312 {
Vernon Mauery224f36a2018-10-25 08:52:23 -0700313 auto seqNum = session->sequenceNums.increment();
Tom Joseph6a560762017-01-10 15:30:28 +0530314 header->sessSeqNum = endian::to_ipmi(seqNum);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500315 }
316}
317
Tom Joseph64703f42017-01-10 17:03:48 +0530318bool verifyPacketIntegrity(const std::vector<uint8_t>& packet,
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700319 const std::shared_ptr<Message> message,
Lei YUce1f4fc2022-07-12 20:22:17 +0800320 size_t payloadLen,
321 const std::shared_ptr<session::Session>& session)
Tom Joseph64703f42017-01-10 17:03:48 +0530322{
Tom Joseph64703f42017-01-10 17:03:48 +0530323 /*
324 * Padding bytes are added to cause the number of bytes in the data range
325 * covered by the AuthCode(Integrity Data) field to be a multiple of 4 bytes
326 * .If present each integrity Pad byte is set to FFh. The following logic
327 * calculates the number of padding bytes added in the IPMI packet.
328 */
Tom Joseph5a2d3ce2017-02-01 20:18:37 +0530329 auto paddingLen = 4 - ((payloadLen + 2) & 3);
Tom Joseph64703f42017-01-10 17:03:48 +0530330
331 auto sessTrailerPos = sizeof(SessionHeader_t) + payloadLen + paddingLen;
332
Zhikui Ren2b1edef2020-07-24 14:32:13 -0700333 // verify packet size includes trailer struct starts at sessTrailerPos
334 if (packet.size() < (sessTrailerPos + sizeof(SessionTrailer_t)))
335 {
336 return false;
337 }
338
Vernon Mauery9e801a22018-10-12 13:20:49 -0700339 auto trailer = reinterpret_cast<const SessionTrailer_t*>(packet.data() +
340 sessTrailerPos);
Tom Joseph64703f42017-01-10 17:03:48 +0530341
342 // Check trailer->padLength against paddingLen, both should match up,
343 // return false if the lengths don't match
Tom Joseph5fa487c2017-01-20 12:42:39 +0530344 if (trailer->padLength != paddingLen)
Tom Joseph64703f42017-01-10 17:03:48 +0530345 {
346 return false;
347 }
348
Tom Joseph64703f42017-01-10 17:03:48 +0530349 auto integrityAlgo = session->getIntegrityAlgo();
350
351 // Check if Integrity data length is as expected, check integrity data
352 // length is same as the length expected for the Integrity Algorithm that
353 // was negotiated during the session open process.
Tom Joseph5fa487c2017-01-20 12:42:39 +0530354 if ((packet.size() - sessTrailerPos - sizeof(SessionTrailer_t)) !=
Vernon Mauery9e801a22018-10-12 13:20:49 -0700355 integrityAlgo->authCodeLength)
Tom Joseph64703f42017-01-10 17:03:48 +0530356 {
357 return false;
358 }
359
360 auto integrityIter = packet.cbegin();
361 std::advance(integrityIter, sessTrailerPos + sizeof(SessionTrailer_t));
362
363 // The integrity data is calculated from the AuthType/Format field up to and
364 // including the field that immediately precedes the AuthCode field itself.
365 size_t length = packet.size() - integrityAlgo->authCodeLength -
366 message::parser::RMCP_SESSION_HEADER_SIZE;
367
368 return integrityAlgo->verifyIntegrityData(packet, length, integrityIter);
369}
370
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700371void addIntegrityData(std::vector<uint8_t>& packet,
Lei YUce1f4fc2022-07-12 20:22:17 +0800372 const std::shared_ptr<Message> message, size_t payloadLen,
373 const std::shared_ptr<session::Session>& session)
Tom Joseph64703f42017-01-10 17:03:48 +0530374{
Tom Joseph64703f42017-01-10 17:03:48 +0530375 // The following logic calculates the number of padding bytes to be added to
376 // IPMI packet. If needed each integrity Pad byte is set to FFh.
Tom Joseph5a2d3ce2017-02-01 20:18:37 +0530377 auto paddingLen = 4 - ((payloadLen + 2) & 3);
Tom Joseph64703f42017-01-10 17:03:48 +0530378 packet.insert(packet.end(), paddingLen, 0xFF);
379
380 packet.resize(packet.size() + sizeof(SessionTrailer_t));
381
Vernon Mauery9e801a22018-10-12 13:20:49 -0700382 auto trailer = reinterpret_cast<SessionTrailer_t*>(
383 packet.data() + packet.size() - sizeof(SessionTrailer_t));
Tom Joseph64703f42017-01-10 17:03:48 +0530384
385 trailer->padLength = paddingLen;
386 trailer->nextHeader = parser::RMCP_MESSAGE_CLASS_IPMI;
387
Vernon Mauery9e801a22018-10-12 13:20:49 -0700388 auto integrityData =
389 session->getIntegrityAlgo()->generateIntegrityData(packet);
Tom Joseph64703f42017-01-10 17:03:48 +0530390
391 packet.insert(packet.end(), integrityData.begin(), integrityData.end());
392}
393
Lei YUce1f4fc2022-07-12 20:22:17 +0800394std::vector<uint8_t>
395 decryptPayload(const std::vector<uint8_t>& packet,
396 const std::shared_ptr<Message> message, size_t payloadLen,
397 const std::shared_ptr<session::Session>& session)
Tom Joseph78478a82017-01-26 14:24:29 +0530398{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700399 return session->getCryptAlgo()->decryptPayload(
400 packet, sizeof(SessionHeader_t), payloadLen);
Tom Joseph78478a82017-01-26 14:24:29 +0530401}
402
Lei YUce1f4fc2022-07-12 20:22:17 +0800403std::vector<uint8_t>
404 encryptPayload(std::shared_ptr<Message> message,
405 const std::shared_ptr<session::Session>& session)
Tom Joseph75362832017-01-26 15:17:04 +0530406{
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700407 return session->getCryptAlgo()->encryptPayload(message->payload);
Tom Joseph75362832017-01-26 15:17:04 +0530408}
409
Tom Joseph4e57ada2016-08-10 06:51:12 -0500410} // namespace internal
411
412} // namespace ipmi20parser
413
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300414#ifdef RMCP_PING
415namespace asfparser
416{
417std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket)
418{
419 auto message = std::make_shared<Message>();
420
421 auto header = reinterpret_cast<AsfMessagePing_t*>(inPacket.data());
422
423 message->payloadType = PayloadType::IPMI;
424 message->rmcpMsgClass = ClassOfMsg::ASF;
425 message->asfMsgTag = header->msgTag;
426
427 return message;
428}
429
430std::vector<uint8_t> flatten(uint8_t asfMsgTag)
431{
432 std::vector<uint8_t> packet(sizeof(AsfMessagePong_t));
433
434 // Insert RMCP header into the Packet
435 auto header = reinterpret_cast<AsfMessagePong_t*>(packet.data());
436 header->ping.rmcp.version = parser::RMCP_VERSION;
437 header->ping.rmcp.reserved = 0x00;
438 header->ping.rmcp.rmcpSeqNum = parser::RMCP_SEQ;
439 header->ping.rmcp.classOfMsg = static_cast<uint8_t>(ClassOfMsg::ASF);
440
441 // No OEM-specific capabilities exist, therefore the second
442 // IANA Enterprise Number contains the same IANA(4542)
443 header->ping.iana = header->iana = endian::to_ipmi(parser::ASF_IANA);
444 header->ping.msgType = static_cast<uint8_t>(RmcpMsgType::PONG);
445 header->ping.msgTag = asfMsgTag;
446 header->ping.reserved = 0x00;
447 header->ping.dataLen =
448 parser::RMCP_ASF_PONG_DATA_LEN; // as per spec 13.2.4,
449
450 header->iana = parser::ASF_IANA;
451 header->oemDefined = 0x00;
452 header->suppEntities = parser::ASF_SUPP_ENT;
453 header->suppInteract = parser::ASF_SUPP_INT;
454 header->reserved1 = 0x00;
455 header->reserved2 = 0x00;
456
457 return packet;
458}
459
460} // namespace asfparser
461#endif // RMCP_PING
462
Tom Joseph4e57ada2016-08-10 06:51:12 -0500463} // namespace message