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