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