Add RMCP Ping support
Added support of RMCP Ping/Pong request and response
(ASF messages).
Tested: Tested using rmcpping tool to send RMCP ping.
Resolves openbmc/phosphor-net-ipmid#15
Signed-off-by: Kirill Pakhomov <k.pakhomov@yadro.com>
Change-Id: Ie5199e6af69860d9406bdd516952b62c3d05793f
diff --git a/message_parsers.cpp b/message_parsers.cpp
index 6703fc3..18f8389 100644
--- a/message_parsers.cpp
+++ b/message_parsers.cpp
@@ -17,24 +17,37 @@
unflatten(std::vector<uint8_t>& inPacket)
{
// Check if the packet has atleast the size of the RMCP Header
- if (inPacket.size() < sizeof(BasicHeader_t))
+ if (inPacket.size() < sizeof(RmcpHeader_t))
{
throw std::runtime_error("RMCP Header missing");
}
- auto rmcpHeaderPtr = reinterpret_cast<BasicHeader_t*>(inPacket.data());
+ auto rmcpHeaderPtr = reinterpret_cast<RmcpHeader_t*>(inPacket.data());
// Verify if the fields in the RMCP header conforms to the specification
if ((rmcpHeaderPtr->version != RMCP_VERSION) ||
(rmcpHeaderPtr->rmcpSeqNum != RMCP_SEQ) ||
- (rmcpHeaderPtr->classOfMsg != RMCP_MESSAGE_CLASS_IPMI))
+ (rmcpHeaderPtr->classOfMsg < static_cast<uint8_t>(ClassOfMsg::ASF) &&
+ rmcpHeaderPtr->classOfMsg > static_cast<uint8_t>(ClassOfMsg::OEM)))
{
throw std::runtime_error("RMCP Header is invalid");
}
+ if (rmcpHeaderPtr->classOfMsg == static_cast<uint8_t>(ClassOfMsg::ASF))
+ {
+#ifndef RMCP_PING
+ throw std::runtime_error("RMCP Ping is not supported");
+#else
+ return std::make_tuple(asfparser::unflatten(inPacket),
+ SessionHeader::IPMI15);
+#endif // RMCP_PING
+ }
+
+ auto sessionHeaderPtr = reinterpret_cast<BasicHeader_t*>(inPacket.data());
+
// Read the Session Header and invoke the parser corresponding to the
// header type
- switch (static_cast<SessionHeader>(rmcpHeaderPtr->format.formatType))
+ switch (static_cast<SessionHeader>(sessionHeaderPtr->format.formatType))
{
case SessionHeader::IPMI15:
{
@@ -96,6 +109,8 @@
message->sessionSeqNum = endian::from_ipmi(header->sessSeqNum);
message->isPacketEncrypted = false;
message->isPacketAuthenticated = false;
+ message->rmcpMsgClass =
+ static_cast<ClassOfMsg>(header->base.rmcp.classOfMsg);
auto payloadLen = header->payloadLength;
@@ -120,10 +135,10 @@
// Insert Session Header into the Packet
auto header = reinterpret_cast<SessionHeader_t*>(packet.data());
- header->base.version = parser::RMCP_VERSION;
- header->base.reserved = 0x00;
- header->base.rmcpSeqNum = parser::RMCP_SEQ;
- header->base.classOfMsg = parser::RMCP_MESSAGE_CLASS_IPMI;
+ header->base.rmcp.version = parser::RMCP_VERSION;
+ header->base.rmcp.reserved = 0x00;
+ header->base.rmcp.rmcpSeqNum = parser::RMCP_SEQ;
+ header->base.rmcp.classOfMsg = static_cast<uint8_t>(ClassOfMsg::IPMI);
header->base.format.formatType =
static_cast<uint8_t>(parser::SessionHeader::IPMI15);
header->sessSeqNum = 0;
@@ -168,6 +183,8 @@
((header->payloadType & PAYLOAD_ENCRYPT_MASK) ? true : false);
message->isPacketAuthenticated =
((header->payloadType & PAYLOAD_AUTH_MASK) ? true : false);
+ message->rmcpMsgClass =
+ static_cast<ClassOfMsg>(header->base.rmcp.classOfMsg);
auto payloadLen = endian::from_ipmi(header->payloadLength);
@@ -202,10 +219,10 @@
std::vector<uint8_t> packet(sizeof(SessionHeader_t));
SessionHeader_t* header = reinterpret_cast<SessionHeader_t*>(packet.data());
- header->base.version = parser::RMCP_VERSION;
- header->base.reserved = 0x00;
- header->base.rmcpSeqNum = parser::RMCP_SEQ;
- header->base.classOfMsg = parser::RMCP_MESSAGE_CLASS_IPMI;
+ header->base.rmcp.version = parser::RMCP_VERSION;
+ header->base.rmcp.reserved = 0x00;
+ header->base.rmcp.rmcpSeqNum = parser::RMCP_SEQ;
+ header->base.rmcp.classOfMsg = static_cast<uint8_t>(ClassOfMsg::IPMI);
header->base.format.formatType =
static_cast<uint8_t>(parser::SessionHeader::IPMI20);
header->payloadType = static_cast<uint8_t>(outMessage->payloadType);
@@ -370,4 +387,53 @@
} // namespace ipmi20parser
+#ifdef RMCP_PING
+namespace asfparser
+{
+std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket)
+{
+ auto message = std::make_shared<Message>();
+
+ auto header = reinterpret_cast<AsfMessagePing_t*>(inPacket.data());
+
+ message->payloadType = PayloadType::IPMI;
+ message->rmcpMsgClass = ClassOfMsg::ASF;
+ message->asfMsgTag = header->msgTag;
+
+ return message;
+}
+
+std::vector<uint8_t> flatten(uint8_t asfMsgTag)
+{
+ std::vector<uint8_t> packet(sizeof(AsfMessagePong_t));
+
+ // Insert RMCP header into the Packet
+ auto header = reinterpret_cast<AsfMessagePong_t*>(packet.data());
+ header->ping.rmcp.version = parser::RMCP_VERSION;
+ header->ping.rmcp.reserved = 0x00;
+ header->ping.rmcp.rmcpSeqNum = parser::RMCP_SEQ;
+ header->ping.rmcp.classOfMsg = static_cast<uint8_t>(ClassOfMsg::ASF);
+
+ // No OEM-specific capabilities exist, therefore the second
+ // IANA Enterprise Number contains the same IANA(4542)
+ header->ping.iana = header->iana = endian::to_ipmi(parser::ASF_IANA);
+ header->ping.msgType = static_cast<uint8_t>(RmcpMsgType::PONG);
+ header->ping.msgTag = asfMsgTag;
+ header->ping.reserved = 0x00;
+ header->ping.dataLen =
+ parser::RMCP_ASF_PONG_DATA_LEN; // as per spec 13.2.4,
+
+ header->iana = parser::ASF_IANA;
+ header->oemDefined = 0x00;
+ header->suppEntities = parser::ASF_SUPP_ENT;
+ header->suppInteract = parser::ASF_SUPP_INT;
+ header->reserved1 = 0x00;
+ header->reserved2 = 0x00;
+
+ return packet;
+}
+
+} // namespace asfparser
+#endif // RMCP_PING
+
} // namespace message