#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 namespace message { std::unique_ptr 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) { std::cerr << "E> Error in Read : " << std::hex << readStatus << "\n"; return nullptr; } // Unflatten the packet std::unique_ptr message; std::tie(message, sessionHeader) = parser::unflatten(packet); auto session = std::get(singletonPool) .getSession(message->bmcSessionID); sessionID = message->bmcSessionID; message->rcSessionID = session->getRCSessionID(); session->updateLastTransactionTime(); return message; } template <> std::unique_ptr Handler::createResponse(std::vector& output, Message& inMessage) { auto outMessage = std::make_unique(); outMessage->payloadType = PayloadType::IPMI; outMessage->payload.resize(sizeof(LAN::header::Response) + output.size() + sizeof(LAN::trailer::Response)); auto reqHeader = reinterpret_cast(inMessage.payload.data()); auto respHeader = reinterpret_cast(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( outMessage->payload.data() + assembledSize); trailer->checksum = crc8bit(&respHeader->rsaddr, assembledSize - 3); return outMessage; } std::unique_ptr Handler::executeCommand(Message& inMessage) { // Get the CommandID to map into the command table auto command = getCommand(inMessage); std::vector 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 inPayload(start, end); output = std::get(singletonPool) .executeCommand(command, inPayload, *this); } else { output = std::get(singletonPool) .executeCommand(command, inMessage.payload, *this); } std::unique_ptr outMessage = nullptr; switch (inMessage.payloadType) { case PayloadType::IPMI: outMessage = createResponse(output, inMessage); break; case PayloadType::OPEN_SESSION_REQUEST: outMessage = createResponse( output, inMessage); break; case PayloadType::RAKP1: outMessage = createResponse(output, inMessage); break; case PayloadType::RAKP3: outMessage = createResponse(output, inMessage); break; case PayloadType::SOL: return outMessage; break; default: break; } outMessage->isPacketEncrypted = inMessage.isPacketEncrypted; outMessage->isPacketAuthenticated = inMessage.isPacketAuthenticated; outMessage->rcSessionID = inMessage.rcSessionID; outMessage->bmcSessionID = inMessage.bmcSessionID; return outMessage; } uint32_t Handler::getCommand(Message& message) { uint32_t command = 0; command |= (static_cast(message.payloadType) << 16); if (message.payloadType == PayloadType::IPMI) { command |= ((reinterpret_cast(message.payload.data())) ->netfn) << 8; command |= (reinterpret_cast(message.payload.data())) ->cmd; } return command; } void Handler::send(Message& 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) { Message outMessage; auto session = std::get(singletonPool).getSession(sessionID); 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) { Message outMessage; auto session = std::get(singletonPool).getSession(sessionID); 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