diff options
author | Vernon Mauery <vernon.mauery@linux.intel.com> | 2018-10-26 10:26:01 -0700 |
---|---|---|
committer | Vernon Mauery <vernon.mauery@linux.intel.com> | 2019-02-04 16:30:42 -0800 |
commit | 7f268e4daa41598610fbd0926b44a3584f527479 (patch) | |
tree | 54cf270635ea8a42b18ffe4144ca13177d7c003f | |
parent | 6f353e868d6fef90e35ef13da7c7ae912becb97a (diff) | |
download | phosphor-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.hpp | 209 | ||||
-rw-r--r-- | message_handler.cpp | 91 | ||||
-rw-r--r-- | message_handler.hpp | 53 |
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 |