#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); return true; } void Handler::updSessionData(std::shared_ptr& inMessage) { session = session::Manager::get().getSession(inMessage->bmcSessionID); sessionID = inMessage->bmcSessionID; inMessage->rcSessionID = session->getRCSessionID(); session->updateLastTransactionTime(); session->channelPtr = channel; session->remotePort(channel->getPort()); uint32_t ipAddr = 0; channel->getRemoteAddress(ipAddr); session->remoteIPAddr(ipAddr); } Handler::~Handler() { try { #ifdef RMCP_PING if (ClassOfMsg::ASF == inMessage->rmcpMsgClass) { sendASF(); } else #endif // RMCP_PING { if (outPayload) { std::shared_ptr outMessage = inMessage->createResponse(*outPayload); if (!outMessage) { return; } 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; } #ifdef RMCP_PING // Execute the Command, possibly asynchronously if (ClassOfMsg::ASF != inMessage->rmcpMsgClass) #endif // RMCP_PING { updSessionData(inMessage); 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) { // Process PayloadType::IPMI only if ipmi is enabled or for sessionless // or for session establisbment command if (this->sessionID == session::sessionZero || session->sessionUserPrivAccess.ipmiEnabled) { 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); command::Table::get().executeCommand(command, inPayload, shared_from_this()); } else { std::vector payload{IPMI_CC_INSUFFICIENT_PRIVILEGE}; outPayload = std::move(payload); } } else { command::Table::get().executeCommand(command, inMessage->payload, shared_from_this()); } } void Handler::writeData(const std::vector& packet) { auto writeStatus = channel->write(packet); if (writeStatus < 0) { throw std::runtime_error("Error in writing to socket"); } } #ifdef RMCP_PING void Handler::sendASF() { // Flatten the packet auto packet = asfparser::flatten(inMessage->asfMsgTag); // Write the packet writeData(packet); } #endif // RMCP_PING void Handler::send(std::shared_ptr outMessage) { // Flatten the packet auto packet = parser::flatten(outMessage, sessionHeader, session); // Write the packet writeData(packet); } void Handler::setChannelInSession() const { session->channelPtr = channel; } void Handler::sendSOLPayload(const std::vector& input) { 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 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