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 using namespace phosphor::logging; 21 22 bool Handler::receive() 23 { 24 std::vector<uint8_t> packet; 25 auto readStatus = 0; 26 27 // Read the packet 28 std::tie(readStatus, packet) = channel->read(); 29 30 // Read of the packet failed 31 if (readStatus < 0) 32 { 33 log<level::ERR>("Error in Read", entry("STATUS=%x", readStatus)); 34 return false; 35 } 36 37 // Unflatten the packet 38 std::tie(inMessage, sessionHeader) = parser::unflatten(packet); 39 40 auto session = std::get<session::Manager&>(singletonPool) 41 .getSession(inMessage->bmcSessionID); 42 43 sessionID = inMessage->bmcSessionID; 44 inMessage->rcSessionID = session->getRCSessionID(); 45 session->updateLastTransactionTime(); 46 session->channelPtr = channel; 47 session->remotePort(channel->getPort()); 48 49 return true; 50 } 51 52 Handler::~Handler() 53 { 54 if (outPayload) 55 { 56 std::shared_ptr<Message> outMessage = 57 inMessage->createResponse(*outPayload); 58 if (!outMessage) 59 { 60 return; 61 } 62 try 63 { 64 send(outMessage); 65 } 66 catch (const std::exception& e) 67 { 68 // send failed, most likely due to a session closure 69 log<level::INFO>("Async RMCP+ reply failed", 70 entry("EXCEPTION=%s", e.what())); 71 } 72 } 73 } 74 75 void Handler::processIncoming() 76 { 77 // Read the incoming IPMI packet 78 if (!receive()) 79 { 80 return; 81 } 82 83 // Execute the Command, possibly asynchronously 84 executeCommand(); 85 86 // send happens during the destructor if a payload was set 87 } 88 89 void Handler::executeCommand() 90 { 91 // Get the CommandID to map into the command table 92 auto command = inMessage->getCommand(); 93 if (inMessage->payloadType == PayloadType::IPMI) 94 { 95 auto session = 96 std::get<session::Manager&>(singletonPool).getSession(sessionID); 97 // Process PayloadType::IPMI only if ipmi is enabled or for sessionless 98 // or for session establisbment command 99 if (this->sessionID == session::sessionZero || 100 session->sessionUserPrivAccess.ipmiEnabled) 101 { 102 if (inMessage->payload.size() < 103 (sizeof(LAN::header::Request) + sizeof(LAN::trailer::Request))) 104 { 105 return; 106 } 107 108 auto start = 109 inMessage->payload.begin() + sizeof(LAN::header::Request); 110 auto end = inMessage->payload.end() - sizeof(LAN::trailer::Request); 111 std::vector<uint8_t> inPayload(start, end); 112 std::get<command::Table&>(singletonPool) 113 .executeCommand(command, inPayload, shared_from_this()); 114 } 115 else 116 { 117 std::vector<uint8_t> payload{IPMI_CC_INSUFFICIENT_PRIVILEGE}; 118 outPayload = std::move(payload); 119 } 120 } 121 else 122 { 123 std::get<command::Table&>(singletonPool) 124 .executeCommand(command, inMessage->payload, shared_from_this()); 125 } 126 } 127 128 void Handler::send(std::shared_ptr<Message> outMessage) 129 { 130 auto session = 131 std::get<session::Manager&>(singletonPool).getSession(sessionID); 132 133 // Flatten the packet 134 auto packet = parser::flatten(outMessage, sessionHeader, session); 135 136 // Write the packet 137 auto writeStatus = channel->write(packet); 138 if (writeStatus < 0) 139 { 140 throw std::runtime_error("Error in writing to socket"); 141 } 142 } 143 144 void Handler::setChannelInSession() const 145 { 146 auto session = 147 std::get<session::Manager&>(singletonPool).getSession(sessionID); 148 149 session->channelPtr = channel; 150 } 151 152 void Handler::sendSOLPayload(const std::vector<uint8_t>& input) 153 { 154 auto session = 155 std::get<session::Manager&>(singletonPool).getSession(sessionID); 156 157 auto outMessage = std::make_shared<Message>(); 158 outMessage->payloadType = PayloadType::SOL; 159 outMessage->payload = input; 160 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled(); 161 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled(); 162 outMessage->rcSessionID = session->getRCSessionID(); 163 outMessage->bmcSessionID = sessionID; 164 165 send(outMessage); 166 } 167 168 void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd, 169 const std::vector<uint8_t>& output) 170 { 171 auto session = 172 std::get<session::Manager&>(singletonPool).getSession(sessionID); 173 174 auto outMessage = std::make_shared<Message>(); 175 outMessage->payloadType = PayloadType::IPMI; 176 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled(); 177 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled(); 178 outMessage->rcSessionID = session->getRCSessionID(); 179 outMessage->bmcSessionID = sessionID; 180 181 outMessage->payload.resize(sizeof(LAN::header::Request) + output.size() + 182 sizeof(LAN::trailer::Request)); 183 184 auto respHeader = 185 reinterpret_cast<LAN::header::Request*>(outMessage->payload.data()); 186 187 // Add IPMI LAN Message Request Header 188 respHeader->rsaddr = LAN::requesterBMCAddress; 189 respHeader->netfn = (netfn << 0x02); 190 respHeader->cs = crc8bit(&(respHeader->rsaddr), 2); 191 respHeader->rqaddr = LAN::responderBMCAddress; 192 respHeader->rqseq = 0; 193 respHeader->cmd = cmd; 194 195 auto assembledSize = sizeof(LAN::header::Request); 196 197 // Copy the output by the execution of the command 198 std::copy(output.begin(), output.end(), 199 outMessage->payload.begin() + assembledSize); 200 assembledSize += output.size(); 201 202 // Add the IPMI LAN Message Trailer 203 auto trailer = reinterpret_cast<LAN::trailer::Request*>( 204 outMessage->payload.data() + assembledSize); 205 206 // Calculate the checksum for the field rqaddr in the header to the 207 // command data, 3 corresponds to size of the fields before rqaddr( rsaddr, 208 // netfn, cs). 209 trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3); 210 211 send(outMessage); 212 } 213 214 } // namespace message 215