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>
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
+