summaryrefslogtreecommitdiffstats
path: root/message_handler.cpp
diff options
context:
space:
mode:
authorTom Joseph <tomjoseph@in.ibm.com>2016-08-10 06:56:25 -0500
committerPatrick Williams <patrick@stwcx.xyz>2016-12-16 11:06:18 +0000
commite6361a21cec0e28149fe77924fdcd3d8c38151f7 (patch)
treec4a1b19b8db20ff2be2bcba8249557a1e75e309f /message_handler.cpp
parent4e57adab1448c56c4f51a1cb7ea481dc390cfe52 (diff)
downloadphosphor-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.cpp182
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
+
OpenPOWER on IntegriCloud