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