blob: f91617196137137d67acec8b9da2c06304e420d9 [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
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700103 auto message = std::make_shared<Message>();
Tom Joseph4e57ada2016-08-10 06:51:12 -0500104
105 auto header = reinterpret_cast<SessionHeader_t*>(inPacket.data());
106
107 message->payloadType = PayloadType::IPMI;
Tom Joseph6a560762017-01-10 15:30:28 +0530108 message->bmcSessionID = endian::from_ipmi(header->sessId);
109 message->sessionSeqNum = endian::from_ipmi(header->sessSeqNum);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500110 message->isPacketEncrypted = false;
111 message->isPacketAuthenticated = false;
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300112 message->rmcpMsgClass =
113 static_cast<ClassOfMsg>(header->base.rmcp.classOfMsg);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500114
Zhikui Ren2b1edef2020-07-24 14:32:13 -0700115 // Confirm the number of data bytes received correlates to
116 // the packet length in the header
Vernon Mauerya71b1ba2021-06-08 15:53:46 -0700117 size_t payloadLen = header->payloadLength;
118 if ((payloadLen == 0) || (inPacket.size() < (sizeof(*header) + payloadLen)))
Zhikui Ren2b1edef2020-07-24 14:32:13 -0700119 {
120 throw std::runtime_error("Invalid data length");
121 }
122
Vernon Mauery9e801a22018-10-12 13:20:49 -0700123 (message->payload)
124 .assign(inPacket.data() + sizeof(SessionHeader_t),
125 inPacket.data() + sizeof(SessionHeader_t) + payloadLen);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500126
127 return message;
128}
129
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700130std::vector<uint8_t> flatten(std::shared_ptr<Message> outMessage,
Vernon Mauery224f36a2018-10-25 08:52:23 -0700131 std::shared_ptr<session::Session> session)
Tom Joseph4e57ada2016-08-10 06:51:12 -0500132{
133 std::vector<uint8_t> packet(sizeof(SessionHeader_t));
134
135 // Insert Session Header into the Packet
136 auto header = reinterpret_cast<SessionHeader_t*>(packet.data());
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300137 header->base.rmcp.version = parser::RMCP_VERSION;
138 header->base.rmcp.reserved = 0x00;
139 header->base.rmcp.rmcpSeqNum = parser::RMCP_SEQ;
140 header->base.rmcp.classOfMsg = static_cast<uint8_t>(ClassOfMsg::IPMI);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500141 header->base.format.formatType =
142 static_cast<uint8_t>(parser::SessionHeader::IPMI15);
143 header->sessSeqNum = 0;
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700144 header->sessId = endian::to_ipmi(outMessage->rcSessionID);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500145
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700146 header->payloadLength = static_cast<uint8_t>(outMessage->payload.size());
Tom Joseph4e57ada2016-08-10 06:51:12 -0500147
148 // Insert the Payload into the Packet
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700149 packet.insert(packet.end(), outMessage->payload.begin(),
150 outMessage->payload.end());
Tom Joseph4e57ada2016-08-10 06:51:12 -0500151
152 // Insert the Session Trailer
153 packet.resize(packet.size() + sizeof(SessionTrailer_t));
Vernon Mauery9e801a22018-10-12 13:20:49 -0700154 auto trailer =
155 reinterpret_cast<SessionTrailer_t*>(packet.data() + packet.size());
Tom Joseph4e57ada2016-08-10 06:51:12 -0500156 trailer->legacyPad = 0x00;
157
158 return packet;
159}
160
161} // namespace ipmi15parser
162
163namespace ipmi20parser
164{
165
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700166std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket)
Tom Joseph4e57ada2016-08-10 06:51:12 -0500167{
168 // Check if the packet has atleast the Session Header
169 if (inPacket.size() < sizeof(SessionHeader_t))
170 {
171 throw std::runtime_error("IPMI2.0 Session Header Missing");
172 }
173
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700174 auto message = std::make_shared<Message>();
Tom Joseph4e57ada2016-08-10 06:51:12 -0500175
176 auto header = reinterpret_cast<SessionHeader_t*>(inPacket.data());
177
Vernon Mauery9e801a22018-10-12 13:20:49 -0700178 message->payloadType = static_cast<PayloadType>(header->payloadType & 0x3F);
Tom Joseph6a560762017-01-10 15:30:28 +0530179 message->bmcSessionID = endian::from_ipmi(header->sessId);
180 message->sessionSeqNum = endian::from_ipmi(header->sessSeqNum);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500181 message->isPacketEncrypted =
182 ((header->payloadType & PAYLOAD_ENCRYPT_MASK) ? true : false);
183 message->isPacketAuthenticated =
184 ((header->payloadType & PAYLOAD_AUTH_MASK) ? true : false);
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300185 message->rmcpMsgClass =
186 static_cast<ClassOfMsg>(header->base.rmcp.classOfMsg);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500187
Vernon Mauerya71b1ba2021-06-08 15:53:46 -0700188 // Confirm the number of data bytes received correlates to
189 // the packet length in the header
190 size_t payloadLen = endian::from_ipmi(header->payloadLength);
191 if ((payloadLen == 0) || (inPacket.size() < (sizeof(*header) + payloadLen)))
192 {
193 throw std::runtime_error("Invalid data length");
194 }
Tom Joseph4e57ada2016-08-10 06:51:12 -0500195
Tom Joseph5fa487c2017-01-20 12:42:39 +0530196 if (message->isPacketAuthenticated)
Tom Joseph64703f42017-01-10 17:03:48 +0530197 {
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700198 if (!(internal::verifyPacketIntegrity(inPacket, message, payloadLen)))
Tom Joseph64703f42017-01-10 17:03:48 +0530199 {
200 throw std::runtime_error("Packet Integrity check failed");
201 }
202 }
203
Tom Joseph78478a82017-01-26 14:24:29 +0530204 // Decrypt the payload if the payload is encrypted
205 if (message->isPacketEncrypted)
206 {
207 // Assign the decrypted payload to the IPMI Message
Vernon Mauery9e801a22018-10-12 13:20:49 -0700208 message->payload =
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700209 internal::decryptPayload(inPacket, message, payloadLen);
Tom Joseph78478a82017-01-26 14:24:29 +0530210 }
211 else
212 {
213 message->payload.assign(inPacket.begin() + sizeof(SessionHeader_t),
214 inPacket.begin() + sizeof(SessionHeader_t) +
Vernon Mauery9e801a22018-10-12 13:20:49 -0700215 payloadLen);
Tom Joseph78478a82017-01-26 14:24:29 +0530216 }
217
Tom Joseph4e57ada2016-08-10 06:51:12 -0500218 return message;
219}
220
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700221std::vector<uint8_t> flatten(std::shared_ptr<Message> outMessage,
Vernon Mauery224f36a2018-10-25 08:52:23 -0700222 std::shared_ptr<session::Session> session)
Tom Joseph4e57ada2016-08-10 06:51:12 -0500223{
224 std::vector<uint8_t> packet(sizeof(SessionHeader_t));
225
226 SessionHeader_t* header = reinterpret_cast<SessionHeader_t*>(packet.data());
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300227 header->base.rmcp.version = parser::RMCP_VERSION;
228 header->base.rmcp.reserved = 0x00;
229 header->base.rmcp.rmcpSeqNum = parser::RMCP_SEQ;
230 header->base.rmcp.classOfMsg = static_cast<uint8_t>(ClassOfMsg::IPMI);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500231 header->base.format.formatType =
232 static_cast<uint8_t>(parser::SessionHeader::IPMI20);
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700233 header->payloadType = static_cast<uint8_t>(outMessage->payloadType);
234 header->sessId = endian::to_ipmi(outMessage->rcSessionID);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500235
236 // Add session sequence number
237 internal::addSequenceNumber(packet, session);
238
Tom Joseph1404bca2017-01-26 14:17:02 +0530239 size_t payloadLen = 0;
240
Tom Joseph75362832017-01-26 15:17:04 +0530241 // Encrypt the payload if needed
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700242 if (outMessage->isPacketEncrypted)
Tom Joseph75362832017-01-26 15:17:04 +0530243 {
244 header->payloadType |= PAYLOAD_ENCRYPT_MASK;
245 auto cipherPayload = internal::encryptPayload(outMessage);
246 payloadLen = cipherPayload.size();
247 header->payloadLength = endian::to_ipmi<uint16_t>(cipherPayload.size());
248
249 // Insert the encrypted payload into the outgoing IPMI packet
250 packet.insert(packet.end(), cipherPayload.begin(), cipherPayload.end());
251 }
252 else
253 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700254 header->payloadLength =
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700255 endian::to_ipmi<uint16_t>(outMessage->payload.size());
256 payloadLen = outMessage->payload.size();
Tom Joseph75362832017-01-26 15:17:04 +0530257
258 // Insert the Payload into the Packet
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700259 packet.insert(packet.end(), outMessage->payload.begin(),
260 outMessage->payload.end());
Tom Joseph75362832017-01-26 15:17:04 +0530261 }
Tom Joseph4e57ada2016-08-10 06:51:12 -0500262
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700263 if (outMessage->isPacketAuthenticated)
Tom Joseph64703f42017-01-10 17:03:48 +0530264 {
Tom Josephb882dbb2019-02-09 23:13:48 +0530265 header = reinterpret_cast<SessionHeader_t*>(packet.data());
266 header->payloadType |= PAYLOAD_AUTH_MASK;
Tom Joseph1404bca2017-01-26 14:17:02 +0530267 internal::addIntegrityData(packet, outMessage, payloadLen);
Tom Joseph64703f42017-01-10 17:03:48 +0530268 }
269
Tom Joseph4e57ada2016-08-10 06:51:12 -0500270 return packet;
271}
272
273namespace internal
274{
275
Vernon Mauery224f36a2018-10-25 08:52:23 -0700276void addSequenceNumber(std::vector<uint8_t>& packet,
277 std::shared_ptr<session::Session> session)
Tom Joseph4e57ada2016-08-10 06:51:12 -0500278{
279 SessionHeader_t* header = reinterpret_cast<SessionHeader_t*>(packet.data());
280
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530281 if (header->sessId == session::sessionZero)
Tom Joseph4e57ada2016-08-10 06:51:12 -0500282 {
283 header->sessSeqNum = 0x00;
284 }
285 else
286 {
Vernon Mauery224f36a2018-10-25 08:52:23 -0700287 auto seqNum = session->sequenceNums.increment();
Tom Joseph6a560762017-01-10 15:30:28 +0530288 header->sessSeqNum = endian::to_ipmi(seqNum);
Tom Joseph4e57ada2016-08-10 06:51:12 -0500289 }
290}
291
Tom Joseph64703f42017-01-10 17:03:48 +0530292bool verifyPacketIntegrity(const std::vector<uint8_t>& packet,
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700293 const std::shared_ptr<Message> message,
294 size_t payloadLen)
Tom Joseph64703f42017-01-10 17:03:48 +0530295{
Tom Joseph64703f42017-01-10 17:03:48 +0530296 /*
297 * Padding bytes are added to cause the number of bytes in the data range
298 * covered by the AuthCode(Integrity Data) field to be a multiple of 4 bytes
299 * .If present each integrity Pad byte is set to FFh. The following logic
300 * calculates the number of padding bytes added in the IPMI packet.
301 */
Tom Joseph5a2d3ce2017-02-01 20:18:37 +0530302 auto paddingLen = 4 - ((payloadLen + 2) & 3);
Tom Joseph64703f42017-01-10 17:03:48 +0530303
304 auto sessTrailerPos = sizeof(SessionHeader_t) + payloadLen + paddingLen;
305
Zhikui Ren2b1edef2020-07-24 14:32:13 -0700306 // verify packet size includes trailer struct starts at sessTrailerPos
307 if (packet.size() < (sessTrailerPos + sizeof(SessionTrailer_t)))
308 {
309 return false;
310 }
311
Vernon Mauery9e801a22018-10-12 13:20:49 -0700312 auto trailer = reinterpret_cast<const SessionTrailer_t*>(packet.data() +
313 sessTrailerPos);
Tom Joseph64703f42017-01-10 17:03:48 +0530314
315 // Check trailer->padLength against paddingLen, both should match up,
316 // return false if the lengths don't match
Tom Joseph5fa487c2017-01-20 12:42:39 +0530317 if (trailer->padLength != paddingLen)
Tom Joseph64703f42017-01-10 17:03:48 +0530318 {
319 return false;
320 }
321
Vernon Maueryae1fda42018-10-15 12:55:34 -0700322 auto session = std::get<session::Manager&>(singletonPool)
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700323 .getSession(message->bmcSessionID);
Tom Joseph64703f42017-01-10 17:03:48 +0530324
325 auto integrityAlgo = session->getIntegrityAlgo();
326
327 // Check if Integrity data length is as expected, check integrity data
328 // length is same as the length expected for the Integrity Algorithm that
329 // was negotiated during the session open process.
Tom Joseph5fa487c2017-01-20 12:42:39 +0530330 if ((packet.size() - sessTrailerPos - sizeof(SessionTrailer_t)) !=
Vernon Mauery9e801a22018-10-12 13:20:49 -0700331 integrityAlgo->authCodeLength)
Tom Joseph64703f42017-01-10 17:03:48 +0530332 {
333 return false;
334 }
335
336 auto integrityIter = packet.cbegin();
337 std::advance(integrityIter, sessTrailerPos + sizeof(SessionTrailer_t));
338
339 // The integrity data is calculated from the AuthType/Format field up to and
340 // including the field that immediately precedes the AuthCode field itself.
341 size_t length = packet.size() - integrityAlgo->authCodeLength -
342 message::parser::RMCP_SESSION_HEADER_SIZE;
343
344 return integrityAlgo->verifyIntegrityData(packet, length, integrityIter);
345}
346
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700347void addIntegrityData(std::vector<uint8_t>& packet,
348 const std::shared_ptr<Message> message, size_t payloadLen)
Tom Joseph64703f42017-01-10 17:03:48 +0530349{
Tom Joseph64703f42017-01-10 17:03:48 +0530350 // The following logic calculates the number of padding bytes to be added to
351 // IPMI packet. If needed each integrity Pad byte is set to FFh.
Tom Joseph5a2d3ce2017-02-01 20:18:37 +0530352 auto paddingLen = 4 - ((payloadLen + 2) & 3);
Tom Joseph64703f42017-01-10 17:03:48 +0530353 packet.insert(packet.end(), paddingLen, 0xFF);
354
355 packet.resize(packet.size() + sizeof(SessionTrailer_t));
356
Vernon Mauery9e801a22018-10-12 13:20:49 -0700357 auto trailer = reinterpret_cast<SessionTrailer_t*>(
358 packet.data() + packet.size() - sizeof(SessionTrailer_t));
Tom Joseph64703f42017-01-10 17:03:48 +0530359
360 trailer->padLength = paddingLen;
361 trailer->nextHeader = parser::RMCP_MESSAGE_CLASS_IPMI;
362
Vernon Maueryae1fda42018-10-15 12:55:34 -0700363 auto session = std::get<session::Manager&>(singletonPool)
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700364 .getSession(message->bmcSessionID);
Tom Joseph64703f42017-01-10 17:03:48 +0530365
Vernon Mauery9e801a22018-10-12 13:20:49 -0700366 auto integrityData =
367 session->getIntegrityAlgo()->generateIntegrityData(packet);
Tom Joseph64703f42017-01-10 17:03:48 +0530368
369 packet.insert(packet.end(), integrityData.begin(), integrityData.end());
370}
371
Tom Joseph78478a82017-01-26 14:24:29 +0530372std::vector<uint8_t> decryptPayload(const std::vector<uint8_t>& packet,
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700373 const std::shared_ptr<Message> message,
374 size_t payloadLen)
Tom Joseph78478a82017-01-26 14:24:29 +0530375{
Vernon Maueryae1fda42018-10-15 12:55:34 -0700376 auto session = std::get<session::Manager&>(singletonPool)
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700377 .getSession(message->bmcSessionID);
Tom Joseph78478a82017-01-26 14:24:29 +0530378
Vernon Mauery9e801a22018-10-12 13:20:49 -0700379 return session->getCryptAlgo()->decryptPayload(
380 packet, sizeof(SessionHeader_t), payloadLen);
Tom Joseph78478a82017-01-26 14:24:29 +0530381}
382
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700383std::vector<uint8_t> encryptPayload(std::shared_ptr<Message> message)
Tom Joseph75362832017-01-26 15:17:04 +0530384{
Vernon Maueryae1fda42018-10-15 12:55:34 -0700385 auto session = std::get<session::Manager&>(singletonPool)
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700386 .getSession(message->bmcSessionID);
Tom Joseph75362832017-01-26 15:17:04 +0530387
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700388 return session->getCryptAlgo()->encryptPayload(message->payload);
Tom Joseph75362832017-01-26 15:17:04 +0530389}
390
Tom Joseph4e57ada2016-08-10 06:51:12 -0500391} // namespace internal
392
393} // namespace ipmi20parser
394
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300395#ifdef RMCP_PING
396namespace asfparser
397{
398std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket)
399{
400 auto message = std::make_shared<Message>();
401
402 auto header = reinterpret_cast<AsfMessagePing_t*>(inPacket.data());
403
404 message->payloadType = PayloadType::IPMI;
405 message->rmcpMsgClass = ClassOfMsg::ASF;
406 message->asfMsgTag = header->msgTag;
407
408 return message;
409}
410
411std::vector<uint8_t> flatten(uint8_t asfMsgTag)
412{
413 std::vector<uint8_t> packet(sizeof(AsfMessagePong_t));
414
415 // Insert RMCP header into the Packet
416 auto header = reinterpret_cast<AsfMessagePong_t*>(packet.data());
417 header->ping.rmcp.version = parser::RMCP_VERSION;
418 header->ping.rmcp.reserved = 0x00;
419 header->ping.rmcp.rmcpSeqNum = parser::RMCP_SEQ;
420 header->ping.rmcp.classOfMsg = static_cast<uint8_t>(ClassOfMsg::ASF);
421
422 // No OEM-specific capabilities exist, therefore the second
423 // IANA Enterprise Number contains the same IANA(4542)
424 header->ping.iana = header->iana = endian::to_ipmi(parser::ASF_IANA);
425 header->ping.msgType = static_cast<uint8_t>(RmcpMsgType::PONG);
426 header->ping.msgTag = asfMsgTag;
427 header->ping.reserved = 0x00;
428 header->ping.dataLen =
429 parser::RMCP_ASF_PONG_DATA_LEN; // as per spec 13.2.4,
430
431 header->iana = parser::ASF_IANA;
432 header->oemDefined = 0x00;
433 header->suppEntities = parser::ASF_SUPP_ENT;
434 header->suppInteract = parser::ASF_SUPP_INT;
435 header->reserved1 = 0x00;
436 header->reserved2 = 0x00;
437
438 return packet;
439}
440
441} // namespace asfparser
442#endif // RMCP_PING
443
Tom Joseph4e57ada2016-08-10 06:51:12 -0500444} // namespace message