#include "message_handler.hpp" #include "command_table.hpp" #include "main.hpp" #include "message.hpp" #include "message_parsers.hpp" #include "sessions_manager.hpp" #include #include #include #include #include using namespace phosphor::logging; namespace message { using namespace phosphor::logging; bool Handler::receive() { std::vector packet; auto readStatus = 0; // Read the packet std::tie(readStatus, packet) = channel->read(); // Read of the packet failed if (readStatus < 0) { log("Error in Read", entry("STATUS=%x", readStatus)); return false; } // Unflatten the packet std::tie(inMessage, sessionHeader) = parser::unflatten(packet); auto session = std::get(singletonPool) .getSession(inMessage->bmcSessionID); sessionID = inMessage->bmcSessionID; inMessage->rcSessionID = session->getRCSessionID(); session->updateLastTransactionTime(); return true; } Handler::~Handler() { if (outPayload) { std::shared_ptr outMessage = inMessage->createResponse(*outPayload); if (!outMessage) { return; } try { send(outMessage); } catch (const std::exception& e) { // send failed, most likely due to a session closure log("Async RMCP+ reply failed", entry("EXCEPTION=%s", e.what())); } } } void Handler::processIncoming() { // Read the incoming IPMI packet if (!receive()) { return; } // Execute the Command, possibly asynchronously executeCommand(); // send happens during the destructor if a payload was set } void Handler::executeCommand() { // Get the CommandID to map into the command table auto command = inMessage->getCommand(); if (inMessage->payloadType == PayloadType::IPMI) { if (inMessage->payload.size() < (sizeof(LAN::header::Request) + sizeof(LAN::trailer::Request))) { return; } auto start = inMessage->payload.begin() + sizeof(LAN::header::Request); auto end = inMessage->payload.end() - sizeof(LAN::trailer::Request); std::vector inPayload(start, end); std::get(singletonPool) .executeCommand(command, inPayload, shared_from_this()); } else { std::get(singletonPool) .executeCommand(command, inMessage->payload, shared_from_this()); } } void Handler::send(std::shared_ptr outMessage) { auto session = std::get(singletonPool).getSession(sessionID); // Flatten the packet auto packet = parser::flatten(outMessage, sessionHeader, session); // Write the packet auto writeStatus = channel->write(packet); if (writeStatus < 0) { throw std::runtime_error("Error in writing to socket"); } } void Handler::setChannelInSession() const { auto session = std::get(singletonPool).getSession(sessionID); session->channelPtr = channel; } void Handler::sendSOLPayload(const std::vector& input) { auto session = std::get(singletonPool).getSession(sessionID); auto outMessage = std::make_shared(); outMessage->payloadType = PayloadType::SOL; outMessage->payload = input; outMessage->isPacketEncrypted = session->isCryptAlgoEnabled(); outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled(); outMessage->rcSessionID = session->getRCSessionID(); outMessage->bmcSessionID = sessionID; send(outMessage); } void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd, const std::vector& output) { auto session = std::get(singletonPool).getSession(sessionID); auto outMessage = std::make_shared(); outMessage->payloadType = PayloadType::IPMI; outMessage->isPacketEncrypted = session->isCryptAlgoEnabled(); outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled(); outMessage->rcSessionID = session->getRCSessionID(); outMessage->bmcSessionID = sessionID; outMessage->payload.resize(sizeof(LAN::header::Request) + output.size() + sizeof(LAN::trailer::Request)); auto respHeader = reinterpret_cast(outMessage->payload.data()); // Add IPMI LAN Message Request Header respHeader->rsaddr = LAN::requesterBMCAddress; respHeader->netfn = (netfn << 0x02); respHeader->cs = crc8bit(&(respHeader->rsaddr), 2); respHeader->rqaddr = LAN::responderBMCAddress; respHeader->rqseq = 0; respHeader->cmd = cmd; auto assembledSize = sizeof(LAN::header::Request); // 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( outMessage->payload.data() + assembledSize); // Calculate the checksum for the field rqaddr in the header to the // command data, 3 corresponds to size of the fields before rqaddr( rsaddr, // netfn, cs). trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3); send(outMessage); } } // namespace message