diff options
author | Tom Joseph <tomjoseph@in.ibm.com> | 2016-08-10 06:56:25 -0500 |
---|---|---|
committer | Patrick Williams <patrick@stwcx.xyz> | 2016-12-16 11:06:18 +0000 |
commit | e6361a21cec0e28149fe77924fdcd3d8c38151f7 (patch) | |
tree | c4a1b19b8db20ff2be2bcba8249557a1e75e309f /message_handler.cpp | |
parent | 4e57adab1448c56c4f51a1cb7ea481dc390cfe52 (diff) | |
download | phosphor-net-ipmid-e6361a21cec0e28149fe77924fdcd3d8c38151f7.tar.gz phosphor-net-ipmid-e6361a21cec0e28149fe77924fdcd3d8c38151f7.zip |
Add Message Handler
IPMI message Handler encapsulates the operations with respective to each
IPMI message.The routines are there to read the message, execute the
command and send the response.
Change-Id: I607416f723510326748b3eba73f3a6557c40dd06
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
Diffstat (limited to 'message_handler.cpp')
-rw-r--r-- | message_handler.cpp | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/message_handler.cpp b/message_handler.cpp new file mode 100644 index 0000000..bfc861e --- /dev/null +++ b/message_handler.cpp @@ -0,0 +1,182 @@ +#include "message_handler.hpp" + +#include <sys/socket.h> + +#include <iostream> +#include <memory> +#include <string> +#include <vector> + +#include "command_table.hpp" +#include "main.hpp" +#include "message.hpp" +#include "message_parsers.hpp" +#include "sessions_manager.hpp" + +namespace message +{ + +std::unique_ptr<Message> Handler::receive() +{ + std::vector<uint8_t> packet; + auto readStatus = 0; + + // Read the packet + std::tie(readStatus, packet) = channel->read(); + + // Read of the packet failed + if (readStatus < 0) + { + std::cerr << "E> Error in Read : " << std::hex << readStatus << "\n"; + return nullptr; + } + + // Unflatten the packet + std::unique_ptr<Message> message; + std::tie(message, sessionHeader) = parser::unflatten(packet); + + + auto session = (std::get<session::Manager&>(singletonPool).getSession( + message->bmcSessionID)).lock(); + + sessionID = message->bmcSessionID; + message->rcSessionID = session->getRCSessionID(); + session->updateLastTransactionTime(); + + return message; +} + +template<> +std::unique_ptr<Message> Handler::createResponse<PayloadType::IPMI>( + std::vector<uint8_t>& output, Message& inMessage) +{ + auto outMessage = std::make_unique<Message>(); + outMessage->rcSessionID = inMessage.rcSessionID; + + 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::unique_ptr<Message> Handler::executeCommand(Message& inMessage) +{ + // Get the CommandID to map into the command table + auto command = getCommand(inMessage); + std::vector<uint8_t> output{}; + + if (inMessage.payloadType == PayloadType::IPMI) + { + if (inMessage.payload.size() < (sizeof(LAN::header::Request) + + sizeof(LAN::trailer::Request))) + { + return nullptr; + } + + auto start = inMessage.payload.begin() + sizeof(LAN::header::Request); + auto end = inMessage.payload.end() - sizeof(LAN::trailer::Request); + std::vector<uint8_t> inPayload(start, end); + + output = std::get<command::Table&>(singletonPool).executeCommand( + command, + inPayload, + *this); + } + else + { + output = std::get<command::Table&>(singletonPool).executeCommand( + command, + inMessage.payload, + *this); + } + + std::unique_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; + default: + break; + + } + + return outMessage; +} + +uint32_t Handler::getCommand(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; +} + +int Handler::send(Message& outMessage) +{ + auto session = (std::get<session::Manager&>(singletonPool).getSession( + sessionID)).lock(); + + // Flatten the packet + auto packet = parser::flatten(outMessage, sessionHeader, *session); + + // Read the packet + auto writeStatus = channel->write(packet); + if (writeStatus < 0) + { + std::cerr << "E> Error in writing : " << std::hex << writeStatus + << "\n"; + } + + return writeStatus; +} + +} //namespace message + |