1 #include "message_handler.hpp" 2 3 #include "command_table.hpp" 4 #include "main.hpp" 5 #include "message.hpp" 6 #include "message_parsers.hpp" 7 #include "sessions_manager.hpp" 8 9 #include <sys/socket.h> 10 11 #include <memory> 12 #include <phosphor-logging/log.hpp> 13 #include <string> 14 #include <vector> 15 16 using namespace phosphor::logging; 17 18 namespace message 19 { 20 21 std::shared_ptr<Message> Handler::receive() 22 { 23 std::vector<uint8_t> packet; 24 auto readStatus = 0; 25 26 // Read the packet 27 std::tie(readStatus, packet) = channel->read(); 28 29 // Read of the packet failed 30 if (readStatus < 0) 31 { 32 log<level::ERR>("Error in Read", entry("STATUS=%x", readStatus)); 33 return nullptr; 34 } 35 36 // Unflatten the packet 37 std::shared_ptr<Message> message; 38 std::tie(message, sessionHeader) = parser::unflatten(packet); 39 40 auto session = std::get<session::Manager&>(singletonPool) 41 .getSession(message->bmcSessionID); 42 43 sessionID = message->bmcSessionID; 44 message->rcSessionID = session->getRCSessionID(); 45 session->updateLastTransactionTime(); 46 47 return message; 48 } 49 50 std::shared_ptr<Message> 51 Handler::executeCommand(std::shared_ptr<Message> inMessage) 52 { 53 // Get the CommandID to map into the command table 54 auto command = inMessage->getCommand(); 55 std::vector<uint8_t> output{}; 56 57 if (inMessage->payloadType == PayloadType::IPMI) 58 { 59 if (inMessage->payload.size() < 60 (sizeof(LAN::header::Request) + sizeof(LAN::trailer::Request))) 61 { 62 return nullptr; 63 } 64 65 auto start = inMessage->payload.begin() + sizeof(LAN::header::Request); 66 auto end = inMessage->payload.end() - sizeof(LAN::trailer::Request); 67 std::vector<uint8_t> inPayload(start, end); 68 69 output = std::get<command::Table&>(singletonPool) 70 .executeCommand(command, inPayload, *this); 71 } 72 else 73 { 74 output = std::get<command::Table&>(singletonPool) 75 .executeCommand(command, inMessage->payload, *this); 76 } 77 return inMessage->createResponse(output); 78 } 79 80 void Handler::send(std::shared_ptr<Message> outMessage) 81 { 82 auto session = 83 std::get<session::Manager&>(singletonPool).getSession(sessionID); 84 85 // Flatten the packet 86 auto packet = parser::flatten(outMessage, sessionHeader, session); 87 88 // Write the packet 89 auto writeStatus = channel->write(packet); 90 if (writeStatus < 0) 91 { 92 throw std::runtime_error("Error in writing to socket"); 93 } 94 } 95 96 void Handler::setChannelInSession() const 97 { 98 auto session = 99 std::get<session::Manager&>(singletonPool).getSession(sessionID); 100 101 session->channelPtr = channel; 102 } 103 104 void Handler::sendSOLPayload(const std::vector<uint8_t>& input) 105 { 106 auto session = 107 std::get<session::Manager&>(singletonPool).getSession(sessionID); 108 109 auto outMessage = std::make_shared<Message>(); 110 outMessage->payloadType = PayloadType::SOL; 111 outMessage->payload = input; 112 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled(); 113 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled(); 114 outMessage->rcSessionID = session->getRCSessionID(); 115 outMessage->bmcSessionID = sessionID; 116 117 send(outMessage); 118 } 119 120 void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd, 121 const std::vector<uint8_t>& output) 122 { 123 auto session = 124 std::get<session::Manager&>(singletonPool).getSession(sessionID); 125 126 auto outMessage = std::make_shared<Message>(); 127 outMessage->payloadType = PayloadType::IPMI; 128 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled(); 129 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled(); 130 outMessage->rcSessionID = session->getRCSessionID(); 131 outMessage->bmcSessionID = sessionID; 132 133 outMessage->payload.resize(sizeof(LAN::header::Request) + output.size() + 134 sizeof(LAN::trailer::Request)); 135 136 auto respHeader = 137 reinterpret_cast<LAN::header::Request*>(outMessage->payload.data()); 138 139 // Add IPMI LAN Message Request Header 140 respHeader->rsaddr = LAN::requesterBMCAddress; 141 respHeader->netfn = (netfn << 0x02); 142 respHeader->cs = crc8bit(&(respHeader->rsaddr), 2); 143 respHeader->rqaddr = LAN::responderBMCAddress; 144 respHeader->rqseq = 0; 145 respHeader->cmd = cmd; 146 147 auto assembledSize = sizeof(LAN::header::Request); 148 149 // Copy the output by the execution of the command 150 std::copy(output.begin(), output.end(), 151 outMessage->payload.begin() + assembledSize); 152 assembledSize += output.size(); 153 154 // Add the IPMI LAN Message Trailer 155 auto trailer = reinterpret_cast<LAN::trailer::Request*>( 156 outMessage->payload.data() + assembledSize); 157 158 // Calculate the checksum for the field rqaddr in the header to the 159 // command data, 3 corresponds to size of the fields before rqaddr( rsaddr, 160 // netfn, cs). 161 trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3); 162 163 send(outMessage); 164 } 165 166 } // namespace message 167