summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVernon Mauery <vernon.mauery@linux.intel.com>2018-10-26 10:26:01 -0700
committerVernon Mauery <vernon.mauery@linux.intel.com>2019-02-04 16:30:42 -0800
commit7f268e4daa41598610fbd0926b44a3584f527479 (patch)
tree54cf270635ea8a42b18ffe4144ca13177d7c003f
parent6f353e868d6fef90e35ef13da7c7ae912becb97a (diff)
downloadphosphor-net-ipmid-7f268e4daa41598610fbd0926b44a3584f527479.tar.gz
phosphor-net-ipmid-7f268e4daa41598610fbd0926b44a3584f527479.zip
netipmid: consolidate message-related things in message.hpp
The message::Handler class was directly manipulating a bunch of stuff on behalf of the message::Message class. This change moves more of the changes into the message::Message class so it can manage its own data. Change-Id: I5d31f6c3c5760207408238d048853e36a60c73e0 Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
-rw-r--r--message.hpp209
-rw-r--r--message_handler.cpp91
-rw-r--r--message_handler.hpp53
3 files changed, 171 insertions, 182 deletions
diff --git a/message.hpp b/message.hpp
index db46c06..ebad490 100644
--- a/message.hpp
+++ b/message.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <memory>
+#include <numeric>
#include <vector>
namespace message
@@ -19,50 +20,6 @@ enum class PayloadType : uint8_t
INVALID = 0xFF,
};
-/**
- * @struct Message
- *
- * IPMI message is data encapsulated in an IPMI Session packet. The IPMI
- * Session packets are encapsulated in RMCP packets, which are encapsulated in
- * UDP datagrams. Refer Section 13.5 of IPMI specification(IPMI Messages
- * Encapsulation Under RMCP). IPMI payload is a special class of data
- * encapsulated in an IPMI session packet.
- */
-struct Message
-{
- static constexpr uint32_t MESSAGE_INVALID_SESSION_ID = 0xBADBADFF;
-
- Message() :
- payloadType(PayloadType::INVALID),
- rcSessionID(Message::MESSAGE_INVALID_SESSION_ID),
- bmcSessionID(Message::MESSAGE_INVALID_SESSION_ID)
- {
- }
-
- ~Message() = default;
- Message(const Message&) = default;
- Message& operator=(const Message&) = default;
- Message(Message&&) = default;
- Message& operator=(Message&&) = default;
-
- bool isPacketEncrypted; // Message's Encryption Status
- bool isPacketAuthenticated; // Message's Authentication Status
- PayloadType payloadType; // Type of message payload (IPMI,SOL ..etc)
- uint32_t rcSessionID; // Remote Client's Session ID
- uint32_t bmcSessionID; // BMC's session ID
- uint32_t sessionSeqNum; // Session Sequence Number
-
- /** @brief Message payload
- *
- * “Payloads” are a capability specified for RMCP+ that enable an IPMI
- * session to carry types of traffic that are in addition to IPMI Messages.
- * Payloads can be ‘standard’ or ‘OEM’.Standard payload types include IPMI
- * Messages, messages for session setup under RMCP+, and the payload for
- * the “Serial Over LAN” capability introduced in IPMI v2.0.
- */
- std::vector<uint8_t> payload;
-};
-
namespace LAN
{
@@ -117,4 +74,168 @@ using Response = Request;
} // namespace LAN
+/**
+ * @brief Calculate 8 bit 2's complement checksum
+ *
+ * Initialize checksum to 0. For each byte, checksum = (checksum + byte)
+ * modulo 256. Then checksum = - checksum. When the checksum and the
+ * bytes are added together, modulo 256, the result should be 0.
+ */
+static inline uint8_t crc8bit(const uint8_t* ptr, const size_t len)
+{
+ return (0x100 - std::accumulate(ptr, ptr + len, 0));
+}
+
+/**
+ * @struct Message
+ *
+ * IPMI message is data encapsulated in an IPMI Session packet. The IPMI
+ * Session packets are encapsulated in RMCP packets, which are encapsulated in
+ * UDP datagrams. Refer Section 13.5 of IPMI specification(IPMI Messages
+ * Encapsulation Under RMCP). IPMI payload is a special class of data
+ * encapsulated in an IPMI session packet.
+ */
+struct Message
+{
+ static constexpr uint32_t MESSAGE_INVALID_SESSION_ID = 0xBADBADFF;
+
+ Message() :
+ payloadType(PayloadType::INVALID),
+ rcSessionID(Message::MESSAGE_INVALID_SESSION_ID),
+ bmcSessionID(Message::MESSAGE_INVALID_SESSION_ID)
+ {
+ }
+
+ /**
+ * @brief Special behavior for copy constructor
+ *
+ * Based on incoming message state, the resulting message will have a
+ * pre-baked state. This is used to simplify the flows for creating a
+ * response message. For each pre-session state, the response message is
+ * actually a different type of message. Once the session has been
+ * established, the response type is the same as the request type.
+ */
+ Message(const Message& other) :
+ isPacketEncrypted(other.isPacketEncrypted),
+ isPacketAuthenticated(other.isPacketAuthenticated),
+ payloadType(other.payloadType), rcSessionID(other.rcSessionID),
+ bmcSessionID(other.bmcSessionID)
+ {
+ // special behavior for rmcp+ session creation
+ if (PayloadType::OPEN_SESSION_REQUEST == other.payloadType)
+ {
+ payloadType = PayloadType::OPEN_SESSION_RESPONSE;
+ }
+ else if (PayloadType::RAKP1 == other.payloadType)
+ {
+ payloadType = PayloadType::RAKP2;
+ }
+ else if (PayloadType::RAKP3 == other.payloadType)
+ {
+ payloadType = PayloadType::RAKP4;
+ }
+ }
+ Message& operator=(const Message&) = default;
+ Message(Message&&) = default;
+ Message& operator=(Message&&) = default;
+ ~Message() = default;
+
+ /**
+ * @brief Extract the command from the IPMI payload
+ *
+ * @return Command ID in the incoming message
+ */
+ uint32_t getCommand()
+ {
+ uint32_t command = 0;
+
+ command |= (static_cast<uint8_t>(payloadType) << 16);
+ if (payloadType == PayloadType::IPMI)
+ {
+ auto request =
+ reinterpret_cast<LAN::header::Request*>(payload.data());
+ command |= request->netfn << 8;
+ command |= request->cmd;
+ }
+ return command;
+ }
+
+ /**
+ * @brief Create the response IPMI message
+ *
+ * The IPMI outgoing message is constructed out of payload and the
+ * corresponding fields are populated. For the payload type IPMI, the
+ * LAN message header and trailer are added.
+ *
+ * @param[in] output - Payload for outgoing message
+ *
+ * @return Outgoing message on success and nullptr on failure
+ */
+ std::shared_ptr<Message> createResponse(std::vector<uint8_t>& output)
+ {
+ // SOL packets don't reply; return NULL
+ if (payloadType == PayloadType::SOL)
+ {
+ return nullptr;
+ }
+ auto outMessage = std::make_shared<Message>(*this);
+
+ if (payloadType == PayloadType::IPMI)
+ {
+ outMessage->payloadType = PayloadType::IPMI;
+
+ outMessage->payload.resize(sizeof(LAN::header::Response) +
+ output.size() +
+ sizeof(LAN::trailer::Response));
+
+ auto reqHeader =
+ reinterpret_cast<LAN::header::Request*>(payload.data());
+ auto respHeader = reinterpret_cast<LAN::header::Response*>(
+ outMessage->payload.data());
+
+ // Add IPMI LAN Message Response Header
+ respHeader->rqaddr = reqHeader->rqaddr;
+ respHeader->netfn = reqHeader->netfn | 0x04;
+ respHeader->cs = crc8bit(&(respHeader->rqaddr), 2);
+ respHeader->rsaddr = reqHeader->rsaddr;
+ respHeader->rqseq = reqHeader->rqseq;
+ respHeader->cmd = reqHeader->cmd;
+
+ auto assembledSize = sizeof(LAN::header::Response);
+
+ // Copy the output by the execution of the command
+ std::copy(output.begin(), output.end(),
+ outMessage->payload.begin() + assembledSize);
+ assembledSize += output.size();
+
+ // Add the IPMI LAN Message Trailer
+ auto trailer = reinterpret_cast<LAN::trailer::Response*>(
+ outMessage->payload.data() + assembledSize);
+ trailer->checksum = crc8bit(&respHeader->rsaddr, assembledSize - 3);
+ }
+ else
+ {
+ outMessage->payload = output;
+ }
+ return outMessage;
+ }
+
+ bool isPacketEncrypted; // Message's Encryption Status
+ bool isPacketAuthenticated; // Message's Authentication Status
+ PayloadType payloadType; // Type of message payload (IPMI,SOL ..etc)
+ uint32_t rcSessionID; // Remote Client's Session ID
+ uint32_t bmcSessionID; // BMC's session ID
+ uint32_t sessionSeqNum; // Session Sequence Number
+
+ /** @brief Message payload
+ *
+ * “Payloads” are a capability specified for RMCP+ that enable an IPMI
+ * session to carry types of traffic that are in addition to IPMI Messages.
+ * Payloads can be ‘standard’ or ‘OEM’.Standard payload types include IPMI
+ * Messages, messages for session setup under RMCP+, and the payload for
+ * the “Serial Over LAN” capability introduced in IPMI v2.0.
+ */
+ std::vector<uint8_t> payload;
+};
+
} // namespace message
diff --git a/message_handler.cpp b/message_handler.cpp
index e98955b..58630d9 100644
--- a/message_handler.cpp
+++ b/message_handler.cpp
@@ -47,49 +47,11 @@ std::shared_ptr<Message> Handler::receive()
return message;
}
-template <>
-std::shared_ptr<Message> Handler::createResponse<PayloadType::IPMI>(
- std::vector<uint8_t>& output, std::shared_ptr<Message> inMessage)
-{
- auto outMessage = std::make_shared<Message>();
- outMessage->payloadType = PayloadType::IPMI;
-
- outMessage->payload.resize(sizeof(LAN::header::Response) + output.size() +
- sizeof(LAN::trailer::Response));
-
- auto reqHeader =
- reinterpret_cast<LAN::header::Request*>(inMessage->payload.data());
- auto respHeader =
- reinterpret_cast<LAN::header::Response*>(outMessage->payload.data());
-
- // Add IPMI LAN Message Response Header
- respHeader->rqaddr = reqHeader->rqaddr;
- respHeader->netfn = reqHeader->netfn | 0x04;
- respHeader->cs = crc8bit(&(respHeader->rqaddr), 2);
- respHeader->rsaddr = reqHeader->rsaddr;
- respHeader->rqseq = reqHeader->rqseq;
- respHeader->cmd = reqHeader->cmd;
-
- auto assembledSize = sizeof(LAN::header::Response);
-
- // Copy the output by the execution of the command
- std::copy(output.begin(), output.end(),
- outMessage->payload.begin() + assembledSize);
- assembledSize += output.size();
-
- // Add the IPMI LAN Message Trailer
- auto trailer = reinterpret_cast<LAN::trailer::Response*>(
- outMessage->payload.data() + assembledSize);
- trailer->checksum = crc8bit(&respHeader->rsaddr, assembledSize - 3);
-
- return outMessage;
-}
-
std::shared_ptr<Message>
Handler::executeCommand(std::shared_ptr<Message> inMessage)
{
// Get the CommandID to map into the command table
- auto command = getCommand(inMessage);
+ auto command = inMessage->getCommand();
std::vector<uint8_t> output{};
if (inMessage->payloadType == PayloadType::IPMI)
@@ -112,56 +74,7 @@ std::shared_ptr<Message>
output = std::get<command::Table&>(singletonPool)
.executeCommand(command, inMessage->payload, *this);
}
-
- std::shared_ptr<Message> outMessage = nullptr;
-
- switch (inMessage->payloadType)
- {
- case PayloadType::IPMI:
- outMessage = createResponse<PayloadType::IPMI>(output, inMessage);
- break;
- case PayloadType::OPEN_SESSION_REQUEST:
- outMessage = createResponse<PayloadType::OPEN_SESSION_RESPONSE>(
- output, inMessage);
- break;
- case PayloadType::RAKP1:
- outMessage = createResponse<PayloadType::RAKP2>(output, inMessage);
- break;
- case PayloadType::RAKP3:
- outMessage = createResponse<PayloadType::RAKP4>(output, inMessage);
- break;
- case PayloadType::SOL:
- return outMessage;
- break;
- default:
- break;
- }
-
- outMessage->isPacketEncrypted = inMessage->isPacketEncrypted;
- outMessage->isPacketAuthenticated = inMessage->isPacketAuthenticated;
- outMessage->rcSessionID = inMessage->rcSessionID;
- outMessage->bmcSessionID = inMessage->bmcSessionID;
-
- return outMessage;
-}
-
-uint32_t Handler::getCommand(std::shared_ptr<Message> message)
-{
- uint32_t command = 0;
-
- command |= (static_cast<uint8_t>(message->payloadType) << 16);
- if (message->payloadType == PayloadType::IPMI)
- {
- command |=
- ((reinterpret_cast<LAN::header::Request*>(message->payload.data()))
- ->netfn)
- << 8;
- command |=
- (reinterpret_cast<LAN::header::Request*>(message->payload.data()))
- ->cmd;
- }
-
- return command;
+ return inMessage->createResponse(output);
}
void Handler::send(std::shared_ptr<Message> outMessage)
diff --git a/message_handler.hpp b/message_handler.hpp
index c620a9d..599b3d6 100644
--- a/message_handler.hpp
+++ b/message_handler.hpp
@@ -6,7 +6,6 @@
#include "sol/console_buffer.hpp"
#include <memory>
-#include <numeric>
namespace message
{
@@ -24,10 +23,10 @@ class Handler
Handler() = delete;
~Handler() = default;
- Handler(const Handler&) = default;
- Handler& operator=(const Handler&) = default;
- Handler(Handler&&) = default;
- Handler& operator=(Handler&&) = default;
+ Handler(const Handler&) = delete;
+ Handler& operator=(const Handler&) = delete;
+ Handler(Handler&&) = delete;
+ Handler& operator=(Handler&&) = delete;
/**
* @brief Receive the IPMI packet
@@ -94,50 +93,6 @@ class Handler
std::shared_ptr<udpsocket::Channel> channel;
parser::SessionHeader sessionHeader = parser::SessionHeader::IPMI20;
-
- /**
- * @brief Create the response IPMI message
- *
- * The IPMI outgoing message is constructed out of payload and the
- * corresponding fields are populated.For the payload type IPMI, the
- * LAN message header and trailer are added.
- *
- * @tparam[in] T - Outgoing message payload type
- * @param[in] output - Payload for outgoing message
- * @param[in] inMessage - Incoming IPMI message
- *
- * @return Outgoing message on success and nullptr on failure
- */
- template <PayloadType T>
- std::shared_ptr<Message> createResponse(std::vector<uint8_t>& output,
- std::shared_ptr<Message> inMessage)
- {
- auto outMessage = std::make_shared<Message>();
- outMessage->payloadType = T;
- outMessage->payload = output;
- return outMessage;
- }
-
- /**
- * @brief Extract the command from the IPMI payload
- *
- * @param[in] message - Incoming message
- *
- * @return Command ID in the incoming message
- */
- uint32_t getCommand(std::shared_ptr<Message> message);
-
- /**
- * @brief Calculate 8 bit 2's complement checksum
- *
- * Initialize checksum to 0. For each byte, checksum = (checksum + byte)
- * modulo 256. Then checksum = - checksum. When the checksum and the
- * bytes are added together, modulo 256, the result should be 0.
- */
- uint8_t crc8bit(const uint8_t* ptr, const size_t len)
- {
- return (0x100 - std::accumulate(ptr, ptr + len, 0));
- }
};
} // namespace message
OpenPOWER on IntegriCloud