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