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